diff --git a/AUTHORS b/AUTHORS
index fd4fd13..2e5fef9 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -800,6 +800,7 @@
 Shanmuga Pandi M <shanmuga.m@samsung.com>
 Shaobo Yan <shaobo.yan@intel.com>
 Shashi Kumar <sk.kumar@samsung.com>
+Shen Yu <shenyu.tcv@gmail.com>
 Sherry Mou <wenjinm@amazon.com>
 Shez Baig <sbaig1@bloomberg.net>
 Shigeki Ohtsu <shigeki.ohtsu@gmail.com>
diff --git a/DEPS b/DEPS
index e77d011..14987a3 100644
--- a/DEPS
+++ b/DEPS
@@ -121,11 +121,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': 'faa73875d2c05c27e6b9863381060befdf5b7ea7',
+  'skia_revision': 'c4745d6e517b2d8d831f98f748e730f64338634c',
   # 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': 'd4d90563417c7f8dfd2fffddf5e1f50ad4ad5d63',
+  'v8_revision': 'b346b550dade4120c0461ee3bd59c763e40a37e2',
   # 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.
@@ -181,7 +181,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': '865a64df6576494643d2eec97f9abbd89b37ed9c',
+  'catapult_revision': '67c39d6acc91227776aa26f91c85f6c75eba20d8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -229,7 +229,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': 'a900bacb58c359419db80ec0bf8c44c66ae4c61f',
+  'spv_tools_revision': '2f004baa99d5faca5087b4cafa3665a74ea3f209',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -245,7 +245,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '110bc7918fc269862bbab2dd9249e80338e15f7d',
+  'dawn_revision': '7c0f0fbf919b07161799d1e000b524bd9a3a5aa6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -826,7 +826,7 @@
   },
 
   'src/third_party/arcore-android-sdk/src': {
-      'url': Var('chromium_git') + '/external/github.com/google-ar/arcore-android-sdk.git' + '@' + '772bed8e2e1bc525a0d10441fa71168a9a87eb69',
+      'url': Var('chromium_git') + '/external/github.com/google-ar/arcore-android-sdk.git' + '@' + '25b4589b55c02344cee5fd5722b06202c8b8776d',
       'condition': 'checkout_android',
   },
 
@@ -1036,7 +1036,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'e1e1e01281079848dc884f272b5a12a49ed56422',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '1d915a646b572fcccead7f73852f33732a7f4f43',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1230,7 +1230,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@987044114d9be5160763ecd27d4f0bf69b2ab8be',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c7a9c5fc2062466f6b5da19812af1053d68408e2',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_proxying_url_loader_factory.cc b/android_webview/browser/aw_proxying_url_loader_factory.cc
index bb1506b4..4639d4a 100644
--- a/android_webview/browser/aw_proxying_url_loader_factory.cc
+++ b/android_webview/browser/aw_proxying_url_loader_factory.cc
@@ -61,11 +61,9 @@
   void OnComplete(const network::URLLoaderCompletionStatus& status) override;
 
   // network::mojom::URLLoader
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override;
@@ -318,14 +316,11 @@
 // URLLoader methods.
 
 void InterceptedRequest::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
-  if (target_loader_) {
-    target_loader_->FollowRedirect(to_be_removed_request_headers,
-                                   modified_request_headers, new_url);
-  }
+  if (target_loader_)
+    target_loader_->FollowRedirect(removed_headers, modified_headers, new_url);
 
   Restart();
 }
diff --git a/android_webview/browser/net_network_service/android_stream_reader_url_loader.cc b/android_webview/browser/net_network_service/android_stream_reader_url_loader.cc
index 06c8cbca..88f5765 100644
--- a/android_webview/browser/net_network_service/android_stream_reader_url_loader.cc
+++ b/android_webview/browser/net_network_service/android_stream_reader_url_loader.cc
@@ -96,9 +96,8 @@
 AndroidStreamReaderURLLoader::~AndroidStreamReaderURLLoader() {}
 
 void AndroidStreamReaderURLLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {}
 void AndroidStreamReaderURLLoader::ProceedWithResponse() {}
 void AndroidStreamReaderURLLoader::SetPriority(net::RequestPriority priority,
diff --git a/android_webview/browser/net_network_service/android_stream_reader_url_loader.h b/android_webview/browser/net_network_service/android_stream_reader_url_loader.h
index 4cfde36..053bdb2 100644
--- a/android_webview/browser/net_network_service/android_stream_reader_url_loader.h
+++ b/android_webview/browser/net_network_service/android_stream_reader_url_loader.h
@@ -38,11 +38,9 @@
   void Start();
 
   // network::mojom::URLLoader overrides:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int intra_priority_value) override;
diff --git a/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java b/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java
index 39284c4..74bd5d1 100644
--- a/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java
+++ b/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java
@@ -4,6 +4,7 @@
 
 package org.chromium.android_webview.test;
 
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
@@ -11,7 +12,9 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.opengl.GLSurfaceView;
+import android.os.Build;
 import android.os.Bundle;
+import android.view.DragEvent;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.SurfaceHolder;
@@ -436,6 +439,12 @@
         return mAwContents.performAccessibilityAction(action, arguments);
     }
 
+    @Override
+    @TargetApi(Build.VERSION_CODES.N)
+    public boolean onDragEvent(DragEvent event) {
+        return mAwContents.onDragEvent(event);
+    }
+
     private class NativeDrawFunctorFactory implements AwContents.NativeDrawFunctorFactory {
         @Override
         public NativeDrawGLFunctor createGLFunctor(long context) {
diff --git a/android_webview/tools/apk_merger.py b/android_webview/tools/apk_merger.py
index c23187a6..14ef0d6d 100755
--- a/android_webview/tools/apk_merger.py
+++ b/android_webview/tools/apk_merger.py
@@ -121,7 +121,7 @@
   # TODO(crbug.com/839191): Remove this once we're plumbing the lib correctly.
   missing_file_set = set(
       f for f in missing_file_set if not os.path.basename(f) ==
-      'libarcore_sdk_c_minimal.so')
+      'libarcore_sdk_c.so')
 
   errors = []
   if unexpected_file_set:
@@ -189,7 +189,7 @@
 
   # TODO(crbug.com/839191): we should pass this in via script arguments.
   if not args.loadable_module_32:
-    args.loadable_module_32.append('libarcore_sdk_c_minimal.so')
+    args.loadable_module_32.append('libarcore_sdk_c.so')
 
   for f in args.loadable_module_32:
     expected_files[f] = not args.uncompress_shared_libraries
diff --git a/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc b/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
index 486a30f..332d866 100644
--- a/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
+++ b/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
@@ -229,6 +229,11 @@
     base::TimeTicks* next_run_time) {
   if (!main_thread_only().task_execution_allowed)
     return false;
+  // Keep this in-sync with
+  // third_party/catapult/tracing/tracing/extras/chrome/event_finder_utils.html
+  // TODO(alexclarke): Rename this event to whatever we end up calling this
+  // after the DoWork / DoDelayed work merge.
+  TRACE_EVENT0("sequence_manager", "ThreadControllerImpl::RunTask");
 
   DCHECK(main_thread_only().task_source);
   bool task_ran = false;
diff --git a/base/task/task_scheduler/platform_native_worker_pool_win.cc b/base/task/task_scheduler/platform_native_worker_pool_win.cc
index 524f0fd..dd58433 100644
--- a/base/task/task_scheduler/platform_native_worker_pool_win.cc
+++ b/base/task/task_scheduler/platform_native_worker_pool_win.cc
@@ -41,10 +41,10 @@
 
   size_t local_num_sequences_before_start;
   {
-    auto transaction(priority_queue_.BeginTransaction());
+    auto transaction = priority_queue_.BeginTransaction();
     DCHECK(!started_);
     started_ = true;
-    local_num_sequences_before_start = transaction->Size();
+    local_num_sequences_before_start = transaction.Size();
   }
 
   // Schedule sequences added to |priority_queue_| before Start().
@@ -91,12 +91,12 @@
 }
 
 scoped_refptr<Sequence> PlatformNativeWorkerPoolWin::GetWork() {
-  auto transaction(priority_queue_.BeginTransaction());
+  auto transaction = priority_queue_.BeginTransaction();
 
   // The PQ should never be empty here as there's a 1:1 correspondence between
   // a call to ScheduleSequence()/SubmitThreadpoolWork() and GetWork().
-  DCHECK(!transaction->IsEmpty());
-  return transaction->PopSequence();
+  DCHECK(!transaction.IsEmpty());
+  return transaction.PopSequence();
 }
 
 void PlatformNativeWorkerPoolWin::OnCanScheduleSequence(
@@ -107,7 +107,7 @@
 
 void PlatformNativeWorkerPoolWin::OnCanScheduleSequence(
     SequenceAndTransaction sequence_and_transaction) {
-  priority_queue_.BeginTransaction()->Push(
+  priority_queue_.BeginTransaction().Push(
       std::move(sequence_and_transaction.sequence),
       sequence_and_transaction.transaction.GetSortKey());
   if (started_) {
diff --git a/base/task/task_scheduler/priority_queue.cc b/base/task/task_scheduler/priority_queue.cc
index 7dbacce..ee52686 100644
--- a/base/task/task_scheduler/priority_queue.cc
+++ b/base/task/task_scheduler/priority_queue.cc
@@ -73,24 +73,39 @@
   DISALLOW_COPY_AND_ASSIGN(SequenceAndSortKey);
 };
 
-PriorityQueue::Transaction::Transaction(PriorityQueue* outer_queue)
-    : auto_lock_(outer_queue->container_lock_), outer_queue_(outer_queue) {}
+PriorityQueue::Transaction::Transaction(Transaction&& other)
+    : outer_queue_(other.outer_queue_) {
+  other.outer_queue_ = nullptr;
+}
 
-PriorityQueue::Transaction::~Transaction() = default;
+PriorityQueue::Transaction::Transaction(PriorityQueue* outer_queue)
+    : outer_queue_(outer_queue) {
+  outer_queue_->container_lock_.Acquire();
+}
+
+PriorityQueue::Transaction::~Transaction() {
+  if (outer_queue_) {
+    outer_queue_->container_lock_.AssertAcquired();
+    outer_queue_->container_lock_.Release();
+  }
+}
 
 void PriorityQueue::Transaction::Push(
     scoped_refptr<Sequence> sequence,
     const SequenceSortKey& sequence_sort_key) {
+  DCHECK(outer_queue_);
   outer_queue_->container_.insert(
       SequenceAndSortKey(std::move(sequence), sequence_sort_key));
 }
 
 const SequenceSortKey& PriorityQueue::Transaction::PeekSortKey() const {
+  DCHECK(outer_queue_);
   DCHECK(!IsEmpty());
   return outer_queue_->container_.Min().sort_key();
 }
 
 scoped_refptr<Sequence> PriorityQueue::Transaction::PopSequence() {
+  DCHECK(outer_queue_);
   DCHECK(!IsEmpty());
 
   // The const_cast on top() is okay since the SequenceAndSortKey is
@@ -106,6 +121,7 @@
 
 bool PriorityQueue::Transaction::RemoveSequence(
     scoped_refptr<Sequence> sequence) {
+  DCHECK(outer_queue_);
   DCHECK(sequence);
 
   if (IsEmpty())
@@ -123,6 +139,7 @@
 
 void PriorityQueue::Transaction::UpdateSortKey(
     SequenceAndTransaction sequence_and_transaction) {
+  DCHECK(outer_queue_);
   DCHECK(sequence_and_transaction.sequence);
 
   if (IsEmpty())
@@ -140,10 +157,12 @@
 }
 
 bool PriorityQueue::Transaction::IsEmpty() const {
+  DCHECK(outer_queue_);
   return outer_queue_->container_.empty();
 }
 
 size_t PriorityQueue::Transaction::Size() const {
+  DCHECK(outer_queue_);
   return outer_queue_->container_.size();
 }
 
@@ -152,7 +171,7 @@
 PriorityQueue::~PriorityQueue() {
   if (is_flush_sequences_on_destroy_enabled_) {
     while (!container_.empty()) {
-      scoped_refptr<Sequence> sequence = BeginTransaction()->PopSequence();
+      scoped_refptr<Sequence> sequence = BeginTransaction().PopSequence();
       {
         Sequence::Transaction sequence_transaction(
             sequence->BeginTransaction());
@@ -165,10 +184,6 @@
   }
 }
 
-std::unique_ptr<PriorityQueue::Transaction> PriorityQueue::BeginTransaction() {
-  return WrapUnique(new Transaction(this));
-}
-
 void PriorityQueue::EnableFlushSequencesOnDestroyForTesting() {
   DCHECK(!is_flush_sequences_on_destroy_enabled_);
   is_flush_sequences_on_destroy_enabled_ = true;
diff --git a/base/task/task_scheduler/priority_queue.h b/base/task/task_scheduler/priority_queue.h
index cd78f73d..76896416 100644
--- a/base/task/task_scheduler/priority_queue.h
+++ b/base/task/task_scheduler/priority_queue.h
@@ -32,6 +32,7 @@
   // operations.
   class BASE_EXPORT Transaction {
    public:
+    Transaction(Transaction&& other);
     ~Transaction();
 
     // Inserts |sequence| in the PriorityQueue with |sequence_sort_key|.
@@ -72,10 +73,7 @@
 
     explicit Transaction(PriorityQueue* outer_queue);
 
-    // Holds the lock of |outer_queue_| for the lifetime of this Transaction.
-    AutoSchedulerLock auto_lock_;
-
-    PriorityQueue* const outer_queue_;
+    PriorityQueue* outer_queue_;
 
     DISALLOW_COPY_AND_ASSIGN(Transaction);
   };
@@ -84,11 +82,8 @@
 
   ~PriorityQueue();
 
-  // Begins a Transaction. This method cannot be called on a thread which has an
-  // active Transaction unless the last Transaction created on the thread was
-  // for the allowed predecessor specified in the constructor of this
-  // PriorityQueue.
-  std::unique_ptr<Transaction> BeginTransaction();
+  // Begins a Transaction.
+  Transaction BeginTransaction() { return Transaction(this); }
 
   // Set the PriorityQueue to empty all its Sequences of Tasks when it is
   // destroyed; needed to prevent memory leaks caused by a reference cycle
diff --git a/base/task/task_scheduler/priority_queue_unittest.cc b/base/task/task_scheduler/priority_queue_unittest.cc
index f9db36edf..b6ef32d 100644
--- a/base/task/task_scheduler/priority_queue_unittest.cc
+++ b/base/task/task_scheduler/priority_queue_unittest.cc
@@ -85,99 +85,99 @@
 
 TEST_F(TaskSchedulerPriorityQueueWithSequencesTest, PushPopPeek) {
   auto transaction = pq.BeginTransaction();
-  EXPECT_TRUE(transaction->IsEmpty());
+  EXPECT_TRUE(transaction.IsEmpty());
 
   // Push |sequence_a| in the PriorityQueue. It becomes the sequence with the
   // highest priority.
-  transaction->Push(sequence_a, sort_key_a);
-  EXPECT_EQ(sort_key_a, transaction->PeekSortKey());
+  transaction.Push(sequence_a, sort_key_a);
+  EXPECT_EQ(sort_key_a, transaction.PeekSortKey());
 
   // Push |sequence_b| in the PriorityQueue. It becomes the sequence with the
   // highest priority.
-  transaction->Push(sequence_b, sort_key_b);
-  EXPECT_EQ(sort_key_b, transaction->PeekSortKey());
+  transaction.Push(sequence_b, sort_key_b);
+  EXPECT_EQ(sort_key_b, transaction.PeekSortKey());
 
   // Push |sequence_c| in the PriorityQueue. |sequence_b| is still the sequence
   // with the highest priority.
-  transaction->Push(sequence_c, sort_key_c);
-  EXPECT_EQ(sort_key_b, transaction->PeekSortKey());
+  transaction.Push(sequence_c, sort_key_c);
+  EXPECT_EQ(sort_key_b, transaction.PeekSortKey());
 
   // Push |sequence_d| in the PriorityQueue. |sequence_b| is still the sequence
   // with the highest priority.
-  transaction->Push(sequence_d, sort_key_d);
-  EXPECT_EQ(sort_key_b, transaction->PeekSortKey());
+  transaction.Push(sequence_d, sort_key_d);
+  EXPECT_EQ(sort_key_b, transaction.PeekSortKey());
 
   // Pop |sequence_b| from the PriorityQueue. |sequence_c| becomes the sequence
   // with the highest priority.
-  EXPECT_EQ(sequence_b, transaction->PopSequence());
-  EXPECT_EQ(sort_key_c, transaction->PeekSortKey());
+  EXPECT_EQ(sequence_b, transaction.PopSequence());
+  EXPECT_EQ(sort_key_c, transaction.PeekSortKey());
 
   // Pop |sequence_c| from the PriorityQueue. |sequence_a| becomes the sequence
   // with the highest priority.
-  EXPECT_EQ(sequence_c, transaction->PopSequence());
-  EXPECT_EQ(sort_key_a, transaction->PeekSortKey());
+  EXPECT_EQ(sequence_c, transaction.PopSequence());
+  EXPECT_EQ(sort_key_a, transaction.PeekSortKey());
 
   // Pop |sequence_a| from the PriorityQueue. |sequence_d| becomes the sequence
   // with the highest priority.
-  EXPECT_EQ(sequence_a, transaction->PopSequence());
-  EXPECT_EQ(sort_key_d, transaction->PeekSortKey());
+  EXPECT_EQ(sequence_a, transaction.PopSequence());
+  EXPECT_EQ(sort_key_d, transaction.PeekSortKey());
 
   // Pop |sequence_d| from the PriorityQueue. It is now empty.
-  EXPECT_EQ(sequence_d, transaction->PopSequence());
-  EXPECT_TRUE(transaction->IsEmpty());
+  EXPECT_EQ(sequence_d, transaction.PopSequence());
+  EXPECT_TRUE(transaction.IsEmpty());
 }
 
 TEST_F(TaskSchedulerPriorityQueueWithSequencesTest, RemoveSequence) {
   auto transaction = pq.BeginTransaction();
-  EXPECT_TRUE(transaction->IsEmpty());
+  EXPECT_TRUE(transaction.IsEmpty());
 
   // Push all test Sequences into the PriorityQueue. |sequence_b|
   // will be the sequence with the highest priority.
-  transaction->Push(sequence_a, sort_key_a);
-  transaction->Push(sequence_b, sort_key_b);
-  transaction->Push(sequence_c, sort_key_c);
-  transaction->Push(sequence_d, sort_key_d);
-  EXPECT_EQ(sort_key_b, transaction->PeekSortKey());
+  transaction.Push(sequence_a, sort_key_a);
+  transaction.Push(sequence_b, sort_key_b);
+  transaction.Push(sequence_c, sort_key_c);
+  transaction.Push(sequence_d, sort_key_d);
+  EXPECT_EQ(sort_key_b, transaction.PeekSortKey());
 
   // Remove |sequence_a| from the PriorityQueue. |sequence_b| is still the
   // sequence with the highest priority.
-  EXPECT_TRUE(transaction->RemoveSequence(sequence_a));
-  EXPECT_EQ(sort_key_b, transaction->PeekSortKey());
+  EXPECT_TRUE(transaction.RemoveSequence(sequence_a));
+  EXPECT_EQ(sort_key_b, transaction.PeekSortKey());
 
   // RemoveSequence() should return false if called on a sequence not in the
   // PriorityQueue.
-  EXPECT_FALSE(transaction->RemoveSequence(sequence_a));
+  EXPECT_FALSE(transaction.RemoveSequence(sequence_a));
 
   // Remove |sequence_b| from the PriorityQueue. |sequence_c| becomes the
   // sequence with the highest priority.
-  EXPECT_TRUE(transaction->RemoveSequence(sequence_b));
-  EXPECT_EQ(sort_key_c, transaction->PeekSortKey());
+  EXPECT_TRUE(transaction.RemoveSequence(sequence_b));
+  EXPECT_EQ(sort_key_c, transaction.PeekSortKey());
 
   // Remove |sequence_d| from the PriorityQueue. |sequence_c| is still the
   // sequence with the highest priority.
-  EXPECT_TRUE(transaction->RemoveSequence(sequence_d));
-  EXPECT_EQ(sort_key_c, transaction->PeekSortKey());
+  EXPECT_TRUE(transaction.RemoveSequence(sequence_d));
+  EXPECT_EQ(sort_key_c, transaction.PeekSortKey());
 
   // Remove |sequence_c| from the PriorityQueue, making it empty.
-  EXPECT_TRUE(transaction->RemoveSequence(sequence_c));
-  EXPECT_TRUE(transaction->IsEmpty());
+  EXPECT_TRUE(transaction.RemoveSequence(sequence_c));
+  EXPECT_TRUE(transaction.IsEmpty());
 
   // Return false if RemoveSequence() is called on an empty PriorityQueue.
-  EXPECT_FALSE(transaction->RemoveSequence(sequence_c));
+  EXPECT_FALSE(transaction.RemoveSequence(sequence_c));
 }
 
 TEST_F(TaskSchedulerPriorityQueueWithSequencesTest, UpdateSortKey) {
   {
     auto transaction = pq.BeginTransaction();
-    EXPECT_TRUE(transaction->IsEmpty());
+    EXPECT_TRUE(transaction.IsEmpty());
 
     // Push all test Sequences into the PriorityQueue. |sequence_b|
     // becomes the sequence with the highest priority.
-    transaction->Push(sequence_a, sort_key_a);
-    transaction->Push(sequence_b, sort_key_b);
-    transaction->Push(sequence_c, sort_key_c);
-    transaction->Push(sequence_d, sort_key_d);
-    EXPECT_EQ(sort_key_b, transaction->PeekSortKey());
+    transaction.Push(sequence_a, sort_key_a);
+    transaction.Push(sequence_b, sort_key_b);
+    transaction.Push(sequence_c, sort_key_c);
+    transaction.Push(sequence_d, sort_key_d);
+    EXPECT_EQ(sort_key_b, transaction.PeekSortKey());
 
     // End |transaction| to respect lock acquisition order (a Sequence lock
     // can't be taken after a PriorityQueue lock).
@@ -192,8 +192,8 @@
         TaskPriority::BEST_EFFORT);
 
     auto transaction = pq.BeginTransaction();
-    transaction->UpdateSortKey(std::move(sequence_b_and_transaction));
-    EXPECT_EQ(sort_key_c, transaction->PeekSortKey());
+    transaction.UpdateSortKey(std::move(sequence_b_and_transaction));
+    EXPECT_EQ(sort_key_c, transaction.PeekSortKey());
   }
 
   {
@@ -206,13 +206,13 @@
         TaskPriority::USER_BLOCKING);
 
     auto transaction = pq.BeginTransaction();
-    transaction->UpdateSortKey(std::move(sequence_c_and_transaction));
+    transaction.UpdateSortKey(std::move(sequence_c_and_transaction));
 
     // Note: |sequence_c| is popped for comparison as |sort_key_c| becomes
     // obsolete. |sequence_a| (USER_VISIBLE priority) becomes the sequence with
     // the highest priority.
-    EXPECT_EQ(sequence_c, transaction->PopSequence());
-    EXPECT_EQ(sort_key_a, transaction->PeekSortKey());
+    EXPECT_EQ(sequence_c, transaction.PopSequence());
+    EXPECT_EQ(sort_key_a, transaction.PeekSortKey());
   }
 
   {
@@ -224,14 +224,14 @@
         TaskPriority::USER_BLOCKING);
 
     auto transaction = pq.BeginTransaction();
-    transaction->UpdateSortKey(std::move(sequence_d_and_transaction));
+    transaction.UpdateSortKey(std::move(sequence_d_and_transaction));
 
     // Note: |sequence_d| is popped for comparison as |sort_key_d| becomes
     // obsolete.
-    EXPECT_EQ(sequence_d, transaction->PopSequence());
+    EXPECT_EQ(sequence_d, transaction.PopSequence());
     // No-op if UpdateSortKey() is called on a Sequence not in the
     // PriorityQueue.
-    EXPECT_EQ(sort_key_a, transaction->PeekSortKey());
+    EXPECT_EQ(sort_key_a, transaction.PeekSortKey());
   }
 
   {
@@ -239,17 +239,17 @@
         SequenceAndTransaction::FromSequence(sequence_d);
 
     auto transaction = pq.BeginTransaction();
-    transaction->UpdateSortKey(std::move(sequence_d_and_transaction));
-    EXPECT_EQ(sequence_a, transaction->PopSequence());
-    EXPECT_EQ(sequence_b, transaction->PopSequence());
+    transaction.UpdateSortKey(std::move(sequence_d_and_transaction));
+    EXPECT_EQ(sequence_a, transaction.PopSequence());
+    EXPECT_EQ(sequence_b, transaction.PopSequence());
   }
 
   // No-op if UpdateSortKey() is called on an empty PriorityQueue.
   auto sequence_b_and_transaction =
       SequenceAndTransaction::FromSequence(sequence_b);
   auto transaction = pq.BeginTransaction();
-  transaction->UpdateSortKey(std::move(sequence_b_and_transaction));
-  EXPECT_TRUE(transaction->IsEmpty());
+  transaction.UpdateSortKey(std::move(sequence_b_and_transaction));
+  EXPECT_TRUE(transaction.IsEmpty());
 }
 
 // Check that creating Transactions on the same thread for 2 unrelated
@@ -272,7 +272,7 @@
   PriorityQueue pq;
 
   // Call BeginTransaction() on this thread and keep the Transaction alive.
-  auto transaction = pq.BeginTransaction();
+  Optional<PriorityQueue::Transaction> transaction(pq.BeginTransaction());
 
   // Call BeginTransaction() on another thread.
   ThreadBeginningTransaction thread_beginning_transaction(&pq);
diff --git a/base/task/task_scheduler/scheduler_lock.h b/base/task/task_scheduler/scheduler_lock.h
index 1b3bfa5..61341fc 100644
--- a/base/task/task_scheduler/scheduler_lock.h
+++ b/base/task/task_scheduler/scheduler_lock.h
@@ -12,6 +12,7 @@
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
 #include "base/task/task_scheduler/scheduler_lock_impl.h"
+#include "base/thread_annotations.h"
 
 namespace base {
 namespace internal {
@@ -55,7 +56,7 @@
 //     Creates a condition variable using this as a lock.
 
 #if DCHECK_IS_ON()
-class SchedulerLock : public SchedulerLockImpl {
+class LOCKABLE SchedulerLock : public SchedulerLockImpl {
  public:
   SchedulerLock() = default;
   explicit SchedulerLock(const SchedulerLock* predecessor)
@@ -64,7 +65,7 @@
       : SchedulerLockImpl(universal_predecessor) {}
 };
 #else   // DCHECK_IS_ON()
-class SchedulerLock : public Lock {
+class LOCKABLE SchedulerLock : public Lock {
  public:
   SchedulerLock() = default;
   explicit SchedulerLock(const SchedulerLock*) {}
@@ -78,13 +79,14 @@
 #endif  // DCHECK_IS_ON()
 
 // Provides the same functionality as base::AutoLock for SchedulerLock.
-class AutoSchedulerLock {
+class SCOPED_LOCKABLE AutoSchedulerLock {
  public:
-  explicit AutoSchedulerLock(SchedulerLock& lock) : lock_(lock) {
+  explicit AutoSchedulerLock(SchedulerLock& lock) EXCLUSIVE_LOCK_FUNCTION(lock)
+      : lock_(lock) {
     lock_.Acquire();
   }
 
-  ~AutoSchedulerLock() {
+  ~AutoSchedulerLock() UNLOCK_FUNCTION() {
     lock_.AssertAcquired();
     lock_.Release();
   }
@@ -95,6 +97,44 @@
   DISALLOW_COPY_AND_ASSIGN(AutoSchedulerLock);
 };
 
+// Informs the clang thread safety analysis that an aliased lock is acquired.
+// Because the clang thread safety analysis doesn't understand aliased locks
+// [1], this code wouldn't compile without AnnotateAcquiredLockAlias:
+//
+// class Example {
+//  public:
+//    SchedulerLock lock_;
+//    int value = 0 GUARDED_BY(lock_);
+// };
+//
+// Example example;
+// SchedulerLock* acquired = &example.lock_;
+// AutoSchedulerLock auto_lock(*acquired);
+// AnnotateAcquiredLockAlias annotate(*acquired, example.lock_);
+// example.value = 42;  // Doesn't compile without |annotate|.
+//
+// [1] https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#no-alias-analysis
+class SCOPED_LOCKABLE AnnotateAcquiredLockAlias {
+ public:
+  // |acquired_lock| is an acquired lock. |lock_alias| is an alias of
+  // |acquired_lock|.
+  AnnotateAcquiredLockAlias(const SchedulerLock& acquired_lock,
+                            const SchedulerLock& lock_alias)
+      EXCLUSIVE_LOCK_FUNCTION(lock_alias)
+      : acquired_lock_(acquired_lock) {
+    DCHECK_EQ(&acquired_lock, &lock_alias);
+    acquired_lock_.AssertAcquired();
+  }
+  ~AnnotateAcquiredLockAlias() UNLOCK_FUNCTION() {
+    acquired_lock_.AssertAcquired();
+  }
+
+ private:
+  const SchedulerLock& acquired_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(AnnotateAcquiredLockAlias);
+};
+
 }  // namespace internal
 }  // namespace base
 
diff --git a/base/task/task_scheduler/scheduler_lock_unittest.cc b/base/task/task_scheduler/scheduler_lock_unittest.cc
index a467f9c..ef8cca5 100644
--- a/base/task/task_scheduler/scheduler_lock_unittest.cc
+++ b/base/task/task_scheduler/scheduler_lock_unittest.cc
@@ -79,6 +79,8 @@
   DISALLOW_COPY_AND_ASSIGN(BasicLockAcquireAndWaitThread);
 };
 
+}  // namespace
+
 TEST(TaskSchedulerLock, Basic) {
   SchedulerLock lock;
   BasicLockTestThread thread(&lock);
@@ -354,6 +356,23 @@
   }
 }
 
+namespace {
+
+class MemberGuardedByLock {
+ public:
+  SchedulerLock lock_;
+  int value GUARDED_BY(lock_) = 0;
+};
+
 }  // namespace
+
+TEST(TaskSchedulerLock, AnnotateAcquiredLockAlias) {
+  MemberGuardedByLock member_guarded_by_lock;
+  SchedulerLock* acquired = &member_guarded_by_lock.lock_;
+  AutoSchedulerLock auto_lock(*acquired);
+  AnnotateAcquiredLockAlias annotate(*acquired, member_guarded_by_lock.lock_);
+  member_guarded_by_lock.value = 42;  // Doesn't compile without |annotate|.
+}
+
 }  // namespace internal
 }  // namespace base
diff --git a/base/task/task_scheduler/scheduler_single_thread_task_runner_manager.cc b/base/task/task_scheduler/scheduler_single_thread_task_runner_manager.cc
index 7be5f19..9d19197 100644
--- a/base/task/task_scheduler/scheduler_single_thread_task_runner_manager.cc
+++ b/base/task/task_scheduler/scheduler_single_thread_task_runner_manager.cc
@@ -103,9 +103,8 @@
   }
 
   scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
-    std::unique_ptr<PriorityQueue::Transaction> transaction(
-        priority_queue_.BeginTransaction());
-    return transaction->IsEmpty() ? nullptr : transaction->PopSequence();
+    auto transaction = priority_queue_.BeginTransaction();
+    return transaction.IsEmpty() ? nullptr : transaction.PopSequence();
   }
 
   void DidRunTask() override {}
@@ -118,10 +117,9 @@
   void ReEnqueueSequence(SequenceAndTransaction sequence_and_transaction) {
     const SequenceSortKey sequence_sort_key =
         sequence_and_transaction.transaction.GetSortKey();
-    std::unique_ptr<PriorityQueue::Transaction> transaction(
-        priority_queue_.BeginTransaction());
-    transaction->Push(std::move(sequence_and_transaction.sequence),
-                      sequence_sort_key);
+    auto transaction = priority_queue_.BeginTransaction();
+    transaction.Push(std::move(sequence_and_transaction.sequence),
+                     sequence_sort_key);
   }
 
   TimeDelta GetSleepTimeout() override { return TimeDelta::Max(); }
diff --git a/base/task/task_scheduler/scheduler_worker_pool_impl.cc b/base/task/task_scheduler/scheduler_worker_pool_impl.cc
index fed6c1eb..bb0d528a 100644
--- a/base/task/task_scheduler/scheduler_worker_pool_impl.cc
+++ b/base/task/task_scheduler/scheduler_worker_pool_impl.cc
@@ -95,9 +95,9 @@
       : outer_(outer) {}
   ~SchedulerWorkerStarter() {
     if (worker_to_start_) {
-      worker_to_start_->Start(outer_->scheduler_worker_observer_);
+      worker_to_start_->Start(outer_->after_start().scheduler_worker_observer);
       for (auto& worker_to_start : additional_workers_to_start_)
-        worker_to_start->Start(outer_->scheduler_worker_observer_);
+        worker_to_start->Start(outer_->after_start().scheduler_worker_observer);
     } else {
       DCHECK(additional_workers_to_start_.empty());
     }
@@ -152,60 +152,91 @@
   // Returns true iff this worker has been within a MAY_BLOCK ScopedBlockingCall
   // for more than |outer_->MayBlockThreshold()|. The max tasks must be
   // incremented if this returns true.
-  bool MustIncrementMaxTasksLockRequired();
+  bool MustIncrementMaxTasksLockRequired()
+      EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_);
 
-  bool is_running_best_effort_task_lock_required() const {
-    outer_->lock_.AssertAcquired();
-    return is_running_best_effort_task_;
+  bool is_running_best_effort_task_lock_required() const
+      EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_) {
+    return read_any().is_running_best_effort_task;
+  }
+
+  // Exposed for AnnotateSchedulerLockAcquired in
+  // SchedulerWorkerPoolImpl::AdjustMaxTasks()
+  const SchedulerLock& lock() const LOCK_RETURNED(outer_->lock_) {
+    return outer_->lock_;
   }
 
  private:
   // Returns true if |worker| is allowed to cleanup and remove itself from the
   // pool. Called from GetWork() when no work is available.
-  bool CanCleanupLockRequired(const SchedulerWorker* worker) const;
+  bool CanCleanupLockRequired(const SchedulerWorker* worker) const
+      EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_);
 
   // Calls cleanup on |worker| and removes it from the pool. Called from
   // GetWork() when no work is available and CanCleanupLockRequired() returns
   // true.
-  void CleanupLockRequired(SchedulerWorker* worker);
+  void CleanupLockRequired(SchedulerWorker* worker)
+      EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_);
 
   // Called in GetWork() when a worker becomes idle.
-  void OnWorkerBecomesIdleLockRequired(SchedulerWorker* worker);
+  void OnWorkerBecomesIdleLockRequired(SchedulerWorker* worker)
+      EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_);
+
+  // Accessed only from the worker thread.
+  struct WorkerOnly {
+    // Number of tasks executed since the last time the
+    // TaskScheduler.NumTasksBetweenWaits histogram was recorded.
+    size_t num_tasks_since_last_wait = 0;
+
+    // Number of tasks executed since the last time the
+    // TaskScheduler.NumTasksBeforeDetach histogram was recorded.
+    size_t num_tasks_since_last_detach = 0;
+
+    // Whether the worker is currently running a task (i.e. GetWork() has
+    // returned a non-empty sequence and DidRunTask() hasn't been called yet).
+    bool is_running_task = false;
+
+#if defined(OS_WIN)
+    std::unique_ptr<win::ScopedWindowsThreadEnvironment> win_thread_environment;
+#endif  // defined(OS_WIN)
+  } worker_only_;
+
+  // Writes from the worker thread protected by |outer_->lock_|. Reads from any
+  // thread, protected by |outer_->lock_| when not on the worker thread.
+  struct WriteWorkerReadAny {
+    // Whether the worker is currently running a TaskPriority::BEST_EFFORT task.
+    bool is_running_best_effort_task = false;
+
+    // Time when MayBlockScopeEntered() was last called. Reset when
+    // BlockingScopeExited() is called.
+    TimeTicks may_block_start_time;
+  } write_worker_read_any_;
+
+  WorkerOnly& worker_only() {
+    DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
+    return worker_only_;
+  }
+
+  WriteWorkerReadAny& write_worker() EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_) {
+    DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
+    return write_worker_read_any_;
+  }
+
+  const WriteWorkerReadAny& read_any() const
+      EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_) {
+    return write_worker_read_any_;
+  }
+
+  const WriteWorkerReadAny& read_worker() const {
+    DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
+    return write_worker_read_any_;
+  }
 
   const TrackedRef<SchedulerWorkerPoolImpl> outer_;
 
-  // Time of the last detach.
-  TimeTicks last_detach_time_;
-
-  // Number of tasks executed since the last time the
-  // TaskScheduler.NumTasksBetweenWaits histogram was recorded.
-  size_t num_tasks_since_last_wait_ = 0;
-
-  // Number of tasks executed since the last time the
-  // TaskScheduler.NumTasksBeforeDetach histogram was recorded.
-  size_t num_tasks_since_last_detach_ = 0;
-
   // Whether |outer_->max_tasks_| was incremented due to a ScopedBlockingCall on
-  // the thread. Access synchronized by |outer_->lock_|.
-  bool incremented_max_tasks_since_blocked_ = false;
-
-  // Time when MayBlockScopeEntered() was last called. Reset when
-  // BlockingScopeExited() is called. Access synchronized by |outer_->lock_|.
-  TimeTicks may_block_start_time_;
-
-  // Whether this worker is currently running a task (i.e. GetWork() has
-  // returned a non-empty sequence and DidRunTask() hasn't been called yet).
-  bool is_running_task_ = false;
-
-  // Whether this worker is currently running a TaskPriority::BEST_EFFORT task.
-  // Writes are made from the worker thread and are protected by
-  // |outer_->lock_|. Reads are made from any thread, they are protected by
-  // |outer_->lock_| when made outside of the worker thread.
-  bool is_running_best_effort_task_ = false;
-
-#if defined(OS_WIN)
-  std::unique_ptr<win::ScopedWindowsThreadEnvironment> win_thread_environment_;
-#endif  // defined(OS_WIN)
+  // the thread.
+  bool incremented_max_tasks_since_blocked_ GUARDED_BY(outer_->lock_) = false;
 
   // Verifies that specific calls are always made from the worker thread.
   THREAD_CHECKER(worker_thread_checker_);
@@ -286,18 +317,22 @@
     int max_best_effort_tasks,
     scoped_refptr<TaskRunner> service_thread_task_runner,
     SchedulerWorkerObserver* scheduler_worker_observer,
-    WorkerEnvironment worker_environment) {
+    WorkerEnvironment worker_environment,
+    Optional<TimeDelta> may_block_threshold) {
   SchedulerWorkerStarter starter(tracked_ref_factory_.GetTrackedRef());
 
   AutoSchedulerLock auto_lock(lock_);
 
   DCHECK(workers_.empty());
 
-  may_block_threshold_ = priority_hint_ == ThreadPriority::NORMAL
-                             ? TimeDelta::FromMicroseconds(
-                                   kMayBlockThresholdMicrosecondsParam.Get())
-                             : kBackgroundMayBlockThreshold;
-  blocked_workers_poll_period_ =
+  in_start().may_block_threshold =
+      may_block_threshold
+          ? may_block_threshold.value()
+          : (priority_hint_ == ThreadPriority::NORMAL
+                 ? TimeDelta::FromMicroseconds(
+                       kMayBlockThresholdMicrosecondsParam.Get())
+                 : kBackgroundMayBlockThreshold);
+  in_start().blocked_workers_poll_period =
       priority_hint_ == ThreadPriority::NORMAL
           ? TimeDelta::FromMicroseconds(
                 kBlockedWorkersPollMicrosecondsParam.Get())
@@ -305,17 +340,18 @@
 
   max_tasks_ = params.max_tasks();
   DCHECK_GE(max_tasks_, 1U);
-  initial_max_tasks_ = max_tasks_;
-  DCHECK_LE(initial_max_tasks_, kMaxNumberOfWorkers);
+  in_start().initial_max_tasks = max_tasks_;
+  DCHECK_LE(in_start().initial_max_tasks, kMaxNumberOfWorkers);
   max_best_effort_tasks_ = max_best_effort_tasks;
-  suggested_reclaim_time_ = params.suggested_reclaim_time();
-  backward_compatibility_ = params.backward_compatibility();
-  worker_environment_ = worker_environment;
+  in_start().suggested_reclaim_time = params.suggested_reclaim_time();
+  in_start().backward_compatibility = params.backward_compatibility();
+  in_start().worker_environment = worker_environment;
+  in_start().service_thread_task_runner = std::move(service_thread_task_runner);
+  in_start().scheduler_worker_observer = scheduler_worker_observer;
 
-  service_thread_task_runner_ = std::move(service_thread_task_runner);
-
-  DCHECK(!scheduler_worker_observer_);
-  scheduler_worker_observer_ = scheduler_worker_observer;
+#if DCHECK_IS_ON()
+  in_start().initialized = true;
+#endif
 
   // The initial number of workers is |num_wake_ups_before_start_| + 1 to try to
   // keep one at least one standby thread at all times (capacity permitting).
@@ -361,7 +397,7 @@
 void SchedulerWorkerPoolImpl::PushSequenceToPriorityQueue(
     SequenceAndTransaction sequence_and_transaction) {
   DCHECK(sequence_and_transaction.sequence);
-  shared_priority_queue_.BeginTransaction()->Push(
+  shared_priority_queue_.BeginTransaction().Push(
       std::move(sequence_and_transaction.sequence),
       sequence_and_transaction.transaction.GetSortKey());
 }
@@ -377,11 +413,11 @@
 int SchedulerWorkerPoolImpl::GetMaxConcurrentNonBlockedTasksDeprecated() const {
 #if DCHECK_IS_ON()
   AutoSchedulerLock auto_lock(lock_);
-  DCHECK_NE(initial_max_tasks_, 0U)
+  DCHECK_NE(after_start().initial_max_tasks, 0U)
       << "GetMaxConcurrentTasksDeprecated() should only be called after the "
       << "worker pool has started.";
 #endif
-  return initial_max_tasks_;
+  return after_start().initial_max_tasks;
 }
 
 void SchedulerWorkerPoolImpl::WaitForWorkersIdleForTesting(size_t n) {
@@ -391,7 +427,7 @@
   DCHECK(!some_workers_cleaned_up_for_testing_)
       << "Workers detached prior to waiting for a specific number of idle "
          "workers. Doing the wait under such conditions is flaky. Consider "
-         "using |suggested_reclaim_time_ = TimeDelta::Max()| for this test.";
+         "setting the suggested reclaim time to TimeDelta::Max() in Start().";
 #endif
 
   WaitForWorkersIdleLockRequiredForTesting(n);
@@ -468,10 +504,6 @@
   return idle_workers_stack_.Size();
 }
 
-void SchedulerWorkerPoolImpl::MaximizeMayBlockThresholdForTesting() {
-  may_block_threshold_ = TimeDelta::Max();
-}
-
 void SchedulerWorkerPoolImpl::ReportHeartbeatMetrics() const {
   AutoSchedulerLock auto_lock(lock_);
   num_workers_histogram_->Add(workers_.size());
@@ -485,12 +517,12 @@
   // TODO(fdoray): A worker should be woken up when the priority of a
   // BEST_EFFORT task is increased and |num_running_best_effort_tasks_| is
   // equal to |max_best_effort_tasks_|.
-  shared_priority_queue_.BeginTransaction()->UpdateSortKey(
+  shared_priority_queue_.BeginTransaction().UpdateSortKey(
       std::move(sequence_and_transaction));
 }
 
 bool SchedulerWorkerPoolImpl::RemoveSequence(scoped_refptr<Sequence> sequence) {
-  return shared_priority_queue_.BeginTransaction()->RemoveSequence(
+  return shared_priority_queue_.BeginTransaction().RemoveSequence(
       std::move(sequence));
 }
 
@@ -528,18 +560,20 @@
   }
 
 #if defined(OS_WIN)
-  if (outer_->worker_environment_ == WorkerEnvironment::COM_MTA) {
+  if (outer_->after_start().worker_environment == WorkerEnvironment::COM_MTA) {
     if (win::GetVersion() >= win::VERSION_WIN8) {
-      win_thread_environment_ = std::make_unique<win::ScopedWinrtInitializer>();
+      worker_only().win_thread_environment =
+          std::make_unique<win::ScopedWinrtInitializer>();
     } else {
-      win_thread_environment_ = std::make_unique<win::ScopedCOMInitializer>(
-          win::ScopedCOMInitializer::kMTA);
+      worker_only().win_thread_environment =
+          std::make_unique<win::ScopedCOMInitializer>(
+              win::ScopedCOMInitializer::kMTA);
     }
-    DCHECK(win_thread_environment_->Succeeded());
+    DCHECK(worker_only().win_thread_environment->Succeeded());
   }
 #endif  // defined(OS_WIN)
 
-  DCHECK_EQ(num_tasks_since_last_wait_, 0U);
+  DCHECK_EQ(worker_only().num_tasks_since_last_wait, 0U);
 
   PlatformThread::SetName(
       StringPrintf("TaskScheduler%sWorker", outer_->pool_label_.c_str()));
@@ -552,8 +586,8 @@
 SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::GetWork(
     SchedulerWorker* worker) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  DCHECK(!is_running_task_);
-  DCHECK(!is_running_best_effort_task_);
+  DCHECK(!worker_only().is_running_task);
+  DCHECK(!read_worker().is_running_best_effort_task);
 
   SchedulerWorkerStarter starter(outer_);
 
@@ -594,10 +628,9 @@
   }
   scoped_refptr<Sequence> sequence;
   {
-    std::unique_ptr<PriorityQueue::Transaction> transaction(
-        outer_->shared_priority_queue_.BeginTransaction());
+    auto transaction = outer_->shared_priority_queue_.BeginTransaction();
 
-    if (transaction->IsEmpty()) {
+    if (transaction.IsEmpty()) {
       // |transaction| is kept alive while |worker| is added to
       // |idle_workers_stack_| to avoid this race:
       // 1. This thread creates a Transaction, finds |shared_priority_queue_|
@@ -616,20 +649,20 @@
     }
 
     // Enforce that no more than |max_best_effort_tasks_| run concurrently.
-    const TaskPriority priority = transaction->PeekSortKey().priority();
+    const TaskPriority priority = transaction.PeekSortKey().priority();
     if (priority == TaskPriority::BEST_EFFORT) {
       AutoSchedulerLock auto_lock(outer_->lock_);
       if (outer_->num_running_best_effort_tasks_ <
           outer_->max_best_effort_tasks_) {
         ++outer_->num_running_best_effort_tasks_;
-        is_running_best_effort_task_ = true;
+        write_worker().is_running_best_effort_task = true;
       } else {
         OnWorkerBecomesIdleLockRequired(worker);
         return nullptr;
       }
     }
 
-    sequence = transaction->PopSequence();
+    sequence = transaction.PopSequence();
   }
   DCHECK(sequence);
 #if DCHECK_IS_ON()
@@ -639,26 +672,31 @@
   }
 #endif
 
-  is_running_task_ = true;
+  worker_only().is_running_task = true;
   return sequence;
 }
 
 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::DidRunTask() {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  DCHECK(may_block_start_time_.is_null());
-  DCHECK(!incremented_max_tasks_since_blocked_);
-  DCHECK(is_running_task_);
+  DCHECK(worker_only().is_running_task);
+  DCHECK(read_worker().may_block_start_time.is_null());
+  // |may_block_start_time| being null unracily implies
+  // |!incremented_max_tasks_since_blocked_|. Skip check on NaCl to avoid unsafe
+  // reference acquisition warning.
+#if !defined(OS_NACL)
+  DCHECK(!TS_UNCHECKED_READ(incremented_max_tasks_since_blocked_));
+#endif
 
-  is_running_task_ = false;
+  worker_only().is_running_task = false;
 
-  if (is_running_best_effort_task_) {
+  if (read_worker().is_running_best_effort_task) {
     AutoSchedulerLock auto_lock(outer_->lock_);
     --outer_->num_running_best_effort_tasks_;
-    is_running_best_effort_task_ = false;
+    write_worker().is_running_best_effort_task = false;
   }
 
-  ++num_tasks_since_last_wait_;
-  ++num_tasks_since_last_detach_;
+  ++worker_only().num_tasks_since_last_wait;
+  ++worker_only().num_tasks_since_last_detach;
 }
 
 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::ReEnqueueSequence(
@@ -671,12 +709,14 @@
 SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::GetSleepTimeout() {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
   // Sleep for an extra 10% to avoid the following pathological case:
-  //   0) A task is running on a timer which matches |suggested_reclaim_time_|.
+
+  //   0) A task is running on a timer which matches
+  //      |after_start().suggested_reclaim_time|.
   //   1) The timer fires and this worker is created by
   //      MaintainAtLeastOneIdleWorkerLockRequired() because the last idle
   //      worker was assigned the task.
-  //   2) This worker begins sleeping |suggested_reclaim_time_| (on top of the
-  //      idle stack).
+  //   2) This worker begins sleeping |after_start().suggested_reclaim_time| (on
+  //      top of the idle stack).
   //   3) The task assigned to the other worker completes and the worker goes
   //      back on the idle stack (this worker is now second on the idle stack;
   //      its GetLastUsedTime() is set to Now()).
@@ -693,11 +733,11 @@
   //   and avoiding churn.
   //
   //   Of course the same problem arises if in (0) the timer matches
-  //   |suggested_reclaim_time_ * 1.1| but it's expected that any timer slower
-  //   than |suggested_reclaim_time_| will cause such churn during long idle
-  //   periods. If this is a problem in practice, the standby thread
-  //   configuration and algorithm should be revisited.
-  return outer_->suggested_reclaim_time_ * 1.1;
+  //   |after_start().suggested_reclaim_time * 1.1| but it's expected that any
+  //   timer slower than |after_start().suggested_reclaim_time| will cause such
+  //   churn during long idle periods. If this is a problem in practice, the
+  //   standby thread configuration and algorithm should be revisited.
+  return outer_->after_start().suggested_reclaim_time * 1.1;
 }
 
 bool SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::
@@ -706,8 +746,9 @@
 
   const TimeTicks last_used_time = worker->GetLastUsedTime();
   return !last_used_time.is_null() &&
-         TimeTicks::Now() - last_used_time >= outer_->suggested_reclaim_time_ &&
-         (outer_->workers_.size() > outer_->initial_max_tasks_ ||
+         TimeTicks::Now() - last_used_time >=
+             outer_->after_start().suggested_reclaim_time &&
+         (outer_->workers_.size() > outer_->after_start().initial_max_tasks ||
           !FeatureList::IsEnabled(kNoDetachBelowInitialCapacity)) &&
          LIKELY(!outer_->worker_cleanup_disallowed_for_testing_);
 }
@@ -716,11 +757,11 @@
     SchedulerWorker* worker) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
 
-  outer_->lock_.AssertAcquired();
-  outer_->num_tasks_before_detach_histogram_->Add(num_tasks_since_last_detach_);
+  outer_->num_tasks_before_detach_histogram_->Add(
+      worker_only().num_tasks_since_last_detach);
   outer_->cleanup_timestamps_.push(TimeTicks::Now());
   worker->Cleanup();
-  outer_->RemoveFromIdleWorkersStackLockRequired(worker);
+  outer_->idle_workers_stack_.Remove(worker);
 
   // Remove the worker from |workers_|.
   auto worker_iter =
@@ -740,14 +781,19 @@
     OnWorkerBecomesIdleLockRequired(SchedulerWorker* worker) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
 
-  outer_->lock_.AssertAcquired();
   // Record the TaskScheduler.NumTasksBetweenWaits histogram. After GetWork()
   // returns nullptr, the SchedulerWorker will perform a wait on its
   // WaitableEvent, so we record how many tasks were ran since the last wait
   // here.
-  outer_->num_tasks_between_waits_histogram_->Add(num_tasks_since_last_wait_);
-  num_tasks_since_last_wait_ = 0;
-  outer_->AddToIdleWorkersStackLockRequired(worker);
+  outer_->num_tasks_between_waits_histogram_->Add(
+      worker_only().num_tasks_since_last_wait);
+  worker_only().num_tasks_since_last_wait = 0;
+
+  // Add the worker to the idle stack.
+  DCHECK(!outer_->idle_workers_stack_.Contains(worker));
+  outer_->idle_workers_stack_.Push(worker);
+  DCHECK_LE(outer_->idle_workers_stack_.Size(), outer_->workers_.size());
+  outer_->idle_workers_stack_cv_for_testing_->Broadcast();
 }
 
 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::OnMainExit(
@@ -771,7 +817,7 @@
 #endif
 
 #if defined(OS_WIN)
-  win_thread_environment_.reset();
+  worker_only().win_thread_environment.reset();
 #endif  // defined(OS_WIN)
 }
 
@@ -780,7 +826,7 @@
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
 
   // Blocking calls made outside of tasks should not influence the max tasks.
-  if (!is_running_task_)
+  if (!worker_only().is_running_task)
     return;
 
   switch (blocking_type) {
@@ -807,10 +853,10 @@
 
     // Cancel the effect of a MAY_BLOCK ScopedBlockingCall instantiated in the
     // same scope.
-    if (!may_block_start_time_.is_null()) {
-      may_block_start_time_ = TimeTicks();
+    if (!read_worker().may_block_start_time.is_null()) {
+      write_worker().may_block_start_time = TimeTicks();
       --outer_->num_pending_may_block_workers_;
-      if (is_running_best_effort_task_)
+      if (read_worker().is_running_best_effort_task)
         --outer_->num_pending_best_effort_may_block_workers_;
     }
   }
@@ -822,21 +868,22 @@
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
 
   // Ignore blocking calls made outside of tasks.
-  if (!is_running_task_)
+  if (!worker_only().is_running_task)
     return;
 
   AutoSchedulerLock auto_lock(outer_->lock_);
   if (incremented_max_tasks_since_blocked_) {
-    outer_->DecrementMaxTasksLockRequired(is_running_best_effort_task_);
+    outer_->DecrementMaxTasksLockRequired(
+        read_worker().is_running_best_effort_task);
   } else {
-    DCHECK(!may_block_start_time_.is_null());
+    DCHECK(!read_worker().may_block_start_time.is_null());
     --outer_->num_pending_may_block_workers_;
-    if (is_running_best_effort_task_)
+    if (read_worker().is_running_best_effort_task)
       --outer_->num_pending_best_effort_may_block_workers_;
   }
 
   incremented_max_tasks_since_blocked_ = false;
-  may_block_start_time_ = TimeTicks();
+  write_worker().may_block_start_time = TimeTicks();
 }
 
 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::MayBlockEntered() {
@@ -847,10 +894,10 @@
     AutoSchedulerLock auto_lock(outer_->lock_);
 
     DCHECK(!incremented_max_tasks_since_blocked_);
-    DCHECK(may_block_start_time_.is_null());
-    may_block_start_time_ = TimeTicks::Now();
+    DCHECK(read_worker().may_block_start_time.is_null());
+    write_worker().may_block_start_time = TimeTicks::Now();
     ++outer_->num_pending_may_block_workers_;
-    if (is_running_best_effort_task_)
+    if (read_worker().is_running_best_effort_task)
       ++outer_->num_pending_best_effort_may_block_workers_;
 
     must_schedule_adjust_max_tasks =
@@ -866,14 +913,14 @@
   bool must_schedule_adjust_max_tasks = false;
   SchedulerWorkerStarter starter(outer_);
   {
-    std::unique_ptr<PriorityQueue::Transaction> transaction(
-        outer_->shared_priority_queue_.BeginTransaction());
+    auto transaction = outer_->shared_priority_queue_.BeginTransaction();
     AutoSchedulerLock auto_lock(outer_->lock_);
 
     DCHECK(!incremented_max_tasks_since_blocked_);
-    DCHECK(may_block_start_time_.is_null());
+    DCHECK(read_worker().may_block_start_time.is_null());
     incremented_max_tasks_since_blocked_ = true;
-    outer_->IncrementMaxTasksLockRequired(is_running_best_effort_task_);
+    outer_->IncrementMaxTasksLockRequired(
+        read_worker().is_running_best_effort_task);
 
     // If the number of workers was less than the old max tasks, PostTask
     // would've handled creating extra workers during WakeUpOneWorker.
@@ -881,7 +928,7 @@
     if (outer_->workers_.size() < outer_->max_tasks_ - 1)
       return;
 
-    if (transaction->IsEmpty()) {
+    if (transaction.IsEmpty()) {
       starter.ScheduleStart(outer_->MaintainAtLeastOneIdleWorkerLockRequired());
     } else {
       // TODO(crbug.com/757897): We may create extra workers in this case:
@@ -901,18 +948,14 @@
 
 bool SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::
     MustIncrementMaxTasksLockRequired() {
-  outer_->lock_.AssertAcquired();
-
   if (!incremented_max_tasks_since_blocked_ &&
-      !may_block_start_time_.is_null() &&
-      TimeTicks::Now() - may_block_start_time_ >= outer_->MayBlockThreshold()) {
+      !read_any().may_block_start_time.is_null() &&
+      TimeTicks::Now() - read_any().may_block_start_time >=
+          outer_->MayBlockThreshold()) {
     incremented_max_tasks_since_blocked_ = true;
 
-    // Reset |may_block_start_time_| so that BlockingScopeExited() knows that it
-    // doesn't have to decrement the number of pending MAY_BLOCK workers.
-    may_block_start_time_ = TimeTicks();
     --outer_->num_pending_may_block_workers_;
-    if (is_running_best_effort_task_)
+    if (read_any().is_running_best_effort_task)
       --outer_->num_pending_best_effort_may_block_workers_;
 
     return true;
@@ -923,8 +966,6 @@
 
 void SchedulerWorkerPoolImpl::WaitForWorkersIdleLockRequiredForTesting(
     size_t n) {
-  lock_.AssertAcquired();
-
   // Make sure workers do not cleanup while watching the idle count.
   AutoReset<bool> ban_cleanups(&worker_cleanup_disallowed_for_testing_, true);
 
@@ -934,8 +975,6 @@
 
 scoped_refptr<SchedulerWorker>
 SchedulerWorkerPoolImpl::WakeUpOneWorkerLockRequired() {
-  lock_.AssertAcquired();
-
   if (workers_.empty()) {
     ++num_wake_ups_before_start_;
     return nullptr;
@@ -970,8 +1009,6 @@
 
 scoped_refptr<SchedulerWorker>
 SchedulerWorkerPoolImpl::MaintainAtLeastOneIdleWorkerLockRequired() {
-  lock_.AssertAcquired();
-
   if (workers_.size() == kMaxNumberOfWorkers)
     return nullptr;
   DCHECK_LT(workers_.size(), kMaxNumberOfWorkers);
@@ -989,28 +1026,8 @@
   return new_worker;
 }
 
-void SchedulerWorkerPoolImpl::AddToIdleWorkersStackLockRequired(
-    SchedulerWorker* worker) {
-  lock_.AssertAcquired();
-
-  DCHECK(!idle_workers_stack_.Contains(worker));
-  idle_workers_stack_.Push(worker);
-
-  DCHECK_LE(idle_workers_stack_.Size(), workers_.size());
-
-  idle_workers_stack_cv_for_testing_->Broadcast();
-}
-
-void SchedulerWorkerPoolImpl::RemoveFromIdleWorkersStackLockRequired(
-    SchedulerWorker* worker) {
-  lock_.AssertAcquired();
-  idle_workers_stack_.Remove(worker);
-}
-
 scoped_refptr<SchedulerWorker>
 SchedulerWorkerPoolImpl::CreateAndRegisterWorkerLockRequired() {
-  lock_.AssertAcquired();
-
   DCHECK_LT(workers_.size(), max_tasks_);
   DCHECK_LT(workers_.size(), kMaxNumberOfWorkers);
   // SchedulerWorker needs |lock_| as a predecessor for its thread lock
@@ -1020,7 +1037,7 @@
       priority_hint_,
       std::make_unique<SchedulerWorkerDelegateImpl>(
           tracked_ref_factory_.GetTrackedRef()),
-      task_tracker_, &lock_, backward_compatibility_);
+      task_tracker_, &lock_, after_start().backward_compatibility);
 
   workers_.push_back(worker);
   DCHECK_LE(workers_.size(), max_tasks_);
@@ -1034,16 +1051,15 @@
 }
 
 size_t SchedulerWorkerPoolImpl::NumberOfExcessWorkersLockRequired() const {
-  lock_.AssertAcquired();
   return std::max<int>(0, workers_.size() - max_tasks_);
 }
 
 void SchedulerWorkerPoolImpl::AdjustMaxTasks() {
-  DCHECK(service_thread_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(
+      after_start().service_thread_task_runner->RunsTasksInCurrentSequence());
 
   SchedulerWorkerStarter starter(tracked_ref_factory_.GetTrackedRef());
-  std::unique_ptr<PriorityQueue::Transaction> transaction(
-      shared_priority_queue_.BeginTransaction());
+  auto transaction = shared_priority_queue_.BeginTransaction();
   AutoSchedulerLock auto_lock(lock_);
 
   const size_t previous_max_tasks = max_tasks_;
@@ -1055,6 +1071,7 @@
     // SchedulerWorkerDelegateImpls.
     SchedulerWorkerDelegateImpl* delegate =
         static_cast<SchedulerWorkerDelegateImpl*>(worker->delegate());
+    AnnotateAcquiredLockAlias annotate(lock_, delegate->lock());
     if (delegate->MustIncrementMaxTasksLockRequired()) {
       IncrementMaxTasksLockRequired(
           delegate->is_running_best_effort_task_lock_required());
@@ -1062,7 +1079,7 @@
   }
 
   // Wake up a worker per pending sequence, capacity permitting.
-  const size_t num_pending_sequences = transaction->Size();
+  const size_t num_pending_sequences = transaction.Size();
   const size_t num_wake_ups_needed =
       std::min(max_tasks_ - previous_max_tasks, num_pending_sequences);
 
@@ -1076,19 +1093,25 @@
 }
 
 TimeDelta SchedulerWorkerPoolImpl::MayBlockThreshold() const {
-  // This value is usually smaller than |blocked_workers_poll_period_| because
-  // we hope than when multiple workers block around the same time, a single
-  // AdjustMaxTasks() call will perform all the necessary max tasks adjustments.
-  return may_block_threshold_;
+  // This value is usually smaller than
+  // |after_start().blocked_workers_poll_period| because we hope than when
+  // multiple workers block around the same time, a single AdjustMaxTasks() call
+  // will perform all the necessary max tasks adjustments.
+  return after_start().may_block_threshold;
 }
 
 void SchedulerWorkerPoolImpl::ScheduleAdjustMaxTasks() {
-  DCHECK(polling_max_tasks_);
-  service_thread_task_runner_->PostDelayedTask(
+  // |polling_max_tasks_| can't change before the task posted below runs. Skip
+  // check on NaCl to avoid unsafe reference acquisition warning.
+#if !defined(OS_NACL)
+  DCHECK(TS_UNCHECKED_READ(polling_max_tasks_));
+#endif
+
+  after_start().service_thread_task_runner->PostDelayedTask(
       FROM_HERE,
       BindOnce(&SchedulerWorkerPoolImpl::AdjustMaxTasksFunction,
                Unretained(this)),
-      blocked_workers_poll_period_);
+      after_start().blocked_workers_poll_period);
 }
 
 bool SchedulerWorkerPoolImpl::MustScheduleAdjustMaxTasksLockRequired() {
@@ -1099,7 +1122,8 @@
 }
 
 void SchedulerWorkerPoolImpl::AdjustMaxTasksFunction() {
-  DCHECK(service_thread_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(
+      after_start().service_thread_task_runner->RunsTasksInCurrentSequence());
 
   AdjustMaxTasks();
   {
@@ -1115,8 +1139,6 @@
 }
 
 bool SchedulerWorkerPoolImpl::ShouldPeriodicallyAdjustMaxTasksLockRequired() {
-  lock_.AssertAcquired();
-
   // The maximum number of best-effort tasks that can run concurrently must be
   // adjusted periodically when (1) the number of best-effort tasks that are
   // currently running is equal to it and (2) there are workers running
@@ -1147,7 +1169,6 @@
 
 void SchedulerWorkerPoolImpl::DecrementMaxTasksLockRequired(
     bool is_running_best_effort_task) {
-  lock_.AssertAcquired();
   --max_tasks_;
   if (is_running_best_effort_task)
     --max_best_effort_tasks_;
@@ -1155,11 +1176,13 @@
 
 void SchedulerWorkerPoolImpl::IncrementMaxTasksLockRequired(
     bool is_running_best_effort_task) {
-  lock_.AssertAcquired();
   ++max_tasks_;
   if (is_running_best_effort_task)
     ++max_best_effort_tasks_;
 }
 
+SchedulerWorkerPoolImpl::InitializedInStart::InitializedInStart() = default;
+SchedulerWorkerPoolImpl::InitializedInStart::~InitializedInStart() = default;
+
 }  // namespace internal
 }  // namespace base
diff --git a/base/task/task_scheduler/scheduler_worker_pool_impl.h b/base/task/task_scheduler/scheduler_worker_pool_impl.h
index 5ef8b6fc..13438bb 100644
--- a/base/task/task_scheduler/scheduler_worker_pool_impl.h
+++ b/base/task/task_scheduler/scheduler_worker_pool_impl.h
@@ -17,6 +17,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #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"
@@ -75,19 +76,22 @@
                           TrackedRef<Delegate> delegate);
 
   // Creates workers following the |params| specification, allowing existing and
-  // future tasks to run. The pool will run at most |max_best_effort_tasks|
-  // unblocked TaskPriority::BEST_EFFORT tasks concurrently. Uses
-  // |service_thread_task_runner| to monitor for blocked threads in the pool. If
-  // specified, |scheduler_worker_observer| will be notified when a worker
-  // enters and exits its main function. It must not be destroyed before
-  // JoinForTesting() has returned (must never be destroyed in production).
-  // |worker_environment| specifies any requested environment to execute the
-  // tasks. Can only be called once. CHECKs on failure.
+  // future tasks to run. The pool runs at most |max_best_effort_tasks|
+  // unblocked BEST_EFFORT tasks concurrently, uses |service_thread_task_runner|
+  // to monitor for blocked tasks, and, if specified, notifies
+  // |scheduler_worker_observer| when a worker enters and exits its main
+  // function (the observer must not be destroyed before JoinForTesting() has
+  // returned). |worker_environment| specifies the environment in which tasks
+  // are executed. |may_block_threshold| is the timeout after which a task in a
+  // MAY_BLOCK ScopedBlockingCall is considered blocked (the pool will choose an
+  // appropriate value if none is specified). Can only be called once. CHECKs on
+  // failure.
   void Start(const SchedulerWorkerPoolParams& params,
              int max_best_effort_tasks,
              scoped_refptr<TaskRunner> service_thread_task_runner,
              SchedulerWorkerObserver* scheduler_worker_observer,
-             WorkerEnvironment worker_environment);
+             WorkerEnvironment worker_environment,
+             Optional<TimeDelta> may_block_threshold = Optional<TimeDelta>());
 
   // Destroying a SchedulerWorkerPoolImpl returned by Create() is not allowed in
   // production; it is always leaked. In tests, it can only be destroyed after
@@ -143,9 +147,6 @@
   // Returns the number of workers that are idle (i.e. not running tasks).
   size_t NumberOfIdleWorkersForTesting() const;
 
-  // Sets the MayBlock waiting threshold to TimeDelta::Max().
-  void MaximizeMayBlockThresholdForTesting();
-
   // Records number of worker and active workers.
   void ReportHeartbeatMetrics() const;
 
@@ -177,9 +178,9 @@
   void PushSequenceToPriorityQueue(
       SequenceAndTransaction sequence_and_transaction);
 
-  // Waits until at least |n| workers are idle. |lock_| must be held to call
-  // this function.
-  void WaitForWorkersIdleLockRequiredForTesting(size_t n);
+  // Waits until at least |n| workers are idle.
+  void WaitForWorkersIdleLockRequiredForTesting(size_t n)
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   // Wakes up the last worker from this worker pool to go idle, if any.
   // Otherwise, creates and starts a worker, if permitted, and wakes it up.
@@ -190,32 +191,26 @@
   // - Instead of starting a worker it creates, returns it and expects that the
   //   caller will start it once |lock_| is released.
   scoped_refptr<SchedulerWorker> WakeUpOneWorkerLockRequired()
-      WARN_UNUSED_RESULT;
+      EXCLUSIVE_LOCKS_REQUIRED(lock_) WARN_UNUSED_RESULT;
 
   // Creates a worker, if needed, to maintain one idle worker, |max_tasks_|
   // permitting. Expects the caller to start the returned worker once |lock_| is
   // released.
   scoped_refptr<SchedulerWorker> MaintainAtLeastOneIdleWorkerLockRequired()
-      WARN_UNUSED_RESULT;
-
-  // Adds |worker| to |idle_workers_stack_|.
-  void AddToIdleWorkersStackLockRequired(SchedulerWorker* worker);
-
-  // Removes |worker| from |idle_workers_stack_|.
-  void RemoveFromIdleWorkersStackLockRequired(SchedulerWorker* worker);
+      EXCLUSIVE_LOCKS_REQUIRED(lock_) WARN_UNUSED_RESULT;
 
   // Returns true if worker cleanup is permitted.
-  bool CanWorkerCleanupForTestingLockRequired();
+  bool CanWorkerCleanupForTestingLockRequired() EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   // Creates a worker, adds it to the pool and returns it. Expects the caller to
-  // start the returned worker. Cannot be called before Start(). Must be called
-  // under the protection of |lock_|.
+  // start the returned worker. Cannot be called before Start().
   scoped_refptr<SchedulerWorker> CreateAndRegisterWorkerLockRequired()
-      WARN_UNUSED_RESULT;
+      EXCLUSIVE_LOCKS_REQUIRED(lock_) WARN_UNUSED_RESULT;
 
   // Returns the number of workers in the pool that should not run tasks due to
   // the pool being over capacity.
-  size_t NumberOfExcessWorkersLockRequired() const;
+  size_t NumberOfExcessWorkersLockRequired() const
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   // Examines the list of SchedulerWorkers and increments |max_tasks_| for each
   // worker that has been within the scope of a MAY_BLOCK ScopedBlockingCall for
@@ -231,7 +226,7 @@
   void ScheduleAdjustMaxTasks();
 
   // Returns true if ScheduleAdjustMaxTasks() must be called.
-  bool MustScheduleAdjustMaxTasksLockRequired();
+  bool MustScheduleAdjustMaxTasksLockRequired() EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   // Calls AdjustMaxTasks() and schedules it again as necessary. May only be
   // called from the service thread.
@@ -239,13 +234,64 @@
 
   // Returns true if AdjustMaxTasks() should periodically be called on
   // |service_thread_task_runner_|.
-  bool ShouldPeriodicallyAdjustMaxTasksLockRequired();
+  bool ShouldPeriodicallyAdjustMaxTasksLockRequired()
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   // Increments/decrements the number of tasks that can run in this pool.
   // |is_running_best_effort_task| indicates whether the worker causing the
   // change is currently running a TaskPriority::BEST_EFFORT task.
-  void DecrementMaxTasksLockRequired(bool is_running_best_effort_task);
-  void IncrementMaxTasksLockRequired(bool is_running_best_effort_task);
+  void DecrementMaxTasksLockRequired(bool is_running_best_effort_task)
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
+  void IncrementMaxTasksLockRequired(bool is_running_best_effort_task)
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+  // Values set at Start() and never modified afterwards.
+  struct InitializedInStart {
+    InitializedInStart();
+    ~InitializedInStart();
+
+#if DCHECK_IS_ON()
+    // Set after all members of this struct are set.
+    bool initialized = false;
+#endif
+
+    // Initial value of |max_tasks_|.
+    size_t initial_max_tasks = 0;
+
+    // Suggested reclaim time for workers.
+    TimeDelta suggested_reclaim_time;
+
+    SchedulerBackwardCompatibility backward_compatibility;
+
+    // Environment to be initialized per worker.
+    WorkerEnvironment worker_environment = WorkerEnvironment::NONE;
+
+    scoped_refptr<TaskRunner> service_thread_task_runner;
+
+    // Optional observer notified when a worker enters and exits its main.
+    SchedulerWorkerObserver* scheduler_worker_observer = nullptr;
+
+    // Threshold after which the max tasks is increased to compensate for a
+    // worker that is within a MAY_BLOCK ScopedBlockingCall.
+    TimeDelta may_block_threshold;
+
+    // The period between calls to AdjustMaxTasks() when the pool is at
+    // capacity.
+    TimeDelta blocked_workers_poll_period;
+  } initialized_in_start_;
+
+  InitializedInStart& in_start() {
+#if DCHECK_IS_ON()
+    DCHECK(!initialized_in_start_.initialized);
+#endif
+    return initialized_in_start_;
+  }
+  const InitializedInStart& after_start() const {
+#if DCHECK_IS_ON()
+    DCHECK(initialized_in_start_.initialized);
+#endif
+    return initialized_in_start_;
+  }
 
   const std::string pool_label_;
   const ThreadPriority priority_hint_;
@@ -253,79 +299,60 @@
   // PriorityQueue from which all threads of this worker pool get work.
   PriorityQueue shared_priority_queue_;
 
-  // Suggested reclaim time for workers. Initialized by Start(). Never modified
-  // afterwards (i.e. can be read without synchronization after Start()).
-  TimeDelta suggested_reclaim_time_;
-
-  SchedulerBackwardCompatibility backward_compatibility_;
-
-  // Synchronizes accesses to |workers_|, |max_tasks_|,
-  // |max_best_effort_tasks_|, |num_running_best_effort_tasks_|,
-  // |num_pending_may_block_workers_|, |idle_workers_stack_|,
-  // |idle_workers_stack_cv_for_testing_|, |num_wake_ups_before_start_|,
-  // |cleanup_timestamps_|, |polling_max_tasks_|,
-  // |worker_cleanup_disallowed_for_testing_|,
-  // |num_workers_cleaned_up_for_testing_|,
-  // |SchedulerWorkerDelegateImpl::is_on_idle_workers_stack_|,
-  // |SchedulerWorkerDelegateImpl::incremented_max_tasks_since_blocked_| and
-  // |SchedulerWorkerDelegateImpl::may_block_start_time_|. Has
-  // |shared_priority_queue_|'s lock as its predecessor so that a worker can be
-  // pushed to |idle_workers_stack_| within the scope of a Transaction (more
-  // details in GetWork()).
+  // Synchronizes accesses to all members of this class which are neither const,
+  // atomic, nor InitializedInStart. Has |shared_priority_queue_|'s lock as its
+  // predecessor so that a worker can be pushed to |idle_workers_stack_| within
+  // the scope of a Transaction (more details in GetWork()).
   mutable SchedulerLock lock_;
 
   // All workers owned by this worker pool.
-  std::vector<scoped_refptr<SchedulerWorker>> workers_;
+  std::vector<scoped_refptr<SchedulerWorker>> workers_ GUARDED_BY(lock_);
 
   // The maximum number of tasks that can run concurrently in this pool. Workers
   // can be added as needed up until there are |max_tasks_| workers.
-  size_t max_tasks_ = 0;
-
-  // Initial value of |max_tasks_| as set in Start().
-  size_t initial_max_tasks_ = 0;
+  size_t max_tasks_ GUARDED_BY(lock_) = 0;
 
   // The maximum number of best-effort tasks that can run concurrently in this
   // pool.
-  int max_best_effort_tasks_ = 0;
+  int max_best_effort_tasks_ GUARDED_BY(lock_) = 0;
 
   // The number of best-effort tasks that are currently running in this pool.
-  int num_running_best_effort_tasks_ = 0;
+  int num_running_best_effort_tasks_ GUARDED_BY(lock_) = 0;
 
   // Number of workers that are within the scope of a MAY_BLOCK
   // ScopedBlockingCall but haven't caused a max task increase yet.
-  int num_pending_may_block_workers_ = 0;
+  int num_pending_may_block_workers_ GUARDED_BY(lock_) = 0;
 
   // Number of workers that are running a TaskPriority::BEST_EFFORT task and are
   // within the scope of a MAY_BLOCK ScopedBlockingCall but haven't caused a max
   // task increase yet.
-  int num_pending_best_effort_may_block_workers_ = 0;
-
-  // Environment to be initialized per worker.
-  WorkerEnvironment worker_environment_ = WorkerEnvironment::NONE;
+  int num_pending_best_effort_may_block_workers_ GUARDED_BY(lock_) = 0;
 
   // Stack of idle workers. Initially, all workers are on this stack. A worker
   // is removed from the stack before its WakeUp() function is called and when
   // it receives work from GetWork() (a worker calls GetWork() when its sleep
   // timeout expires, even if its WakeUp() method hasn't been called). A worker
   // is pushed on this stack when it receives nullptr from GetWork().
-  SchedulerWorkerStack idle_workers_stack_;
+  SchedulerWorkerStack idle_workers_stack_ GUARDED_BY(lock_);
 
   // Signaled when a worker is added to the idle workers stack.
-  std::unique_ptr<ConditionVariable> idle_workers_stack_cv_for_testing_;
+  std::unique_ptr<ConditionVariable> idle_workers_stack_cv_for_testing_
+      GUARDED_BY(lock_);
 
   // Number of wake ups that occurred before Start(). Never modified after
   // Start() (i.e. can be read without synchronization after Start()).
-  int num_wake_ups_before_start_ = 0;
+  int num_wake_ups_before_start_ GUARDED_BY(lock_) = 0;
 
   // Stack that contains the timestamps of when workers get cleaned up.
   // Timestamps get popped off the stack as new workers are added.
-  base::stack<TimeTicks, std::vector<TimeTicks>> cleanup_timestamps_;
+  base::stack<TimeTicks, std::vector<TimeTicks>> cleanup_timestamps_
+      GUARDED_BY(lock_);
 
   // Whether we are currently polling for necessary adjustments to |max_tasks_|.
-  bool polling_max_tasks_ = false;
+  bool polling_max_tasks_ GUARDED_BY(lock_) = false;
 
   // Indicates to the delegates that workers are not permitted to cleanup.
-  bool worker_cleanup_disallowed_for_testing_ = false;
+  bool worker_cleanup_disallowed_for_testing_ GUARDED_BY(lock_) = false;
 
   // Counts the number of workers cleaned up since the last call to
   // WaitForWorkersCleanedUpForTesting() (or Start() if it wasn't called yet).
@@ -333,21 +360,15 @@
   // incremented. Tests with a custom |suggested_reclaim_time_| can wait on a
   // specific number of workers being cleaned up via
   // WaitForWorkersCleanedUpForTesting().
-  size_t num_workers_cleaned_up_for_testing_ = 0;
+  size_t num_workers_cleaned_up_for_testing_ GUARDED_BY(lock_) = 0;
 #if DCHECK_IS_ON()
-  bool some_workers_cleaned_up_for_testing_ = false;
+  bool some_workers_cleaned_up_for_testing_ GUARDED_BY(lock_) = false;
 #endif
 
   // Signaled, if non-null, when |num_workers_cleaned_up_for_testing_| is
   // incremented.
-  std::unique_ptr<ConditionVariable> num_workers_cleaned_up_for_testing_cv_;
-
-  // Threshold after which the max tasks is increased to compensate for a
-  // worker that is within a MAY_BLOCK ScopedBlockingCall.
-  TimeDelta may_block_threshold_;
-
-  // The period between calls to AdjustMaxTasks() when the pool is at capacity.
-  TimeDelta blocked_workers_poll_period_;
+  std::unique_ptr<ConditionVariable> num_workers_cleaned_up_for_testing_cv_
+      GUARDED_BY(lock_);
 
 #if DCHECK_IS_ON()
   // Set at the start of JoinForTesting().
@@ -374,18 +395,13 @@
   // Intentionally leaked.
   HistogramBase* const num_active_workers_histogram_;
 
-  scoped_refptr<TaskRunner> service_thread_task_runner_;
-
-  // Optional observer notified when a worker enters and exits its main
-  // function. Set in Start() and never modified afterwards.
-  SchedulerWorkerObserver* scheduler_worker_observer_ = nullptr;
-
   // Ensures recently cleaned up workers (ref.
   // SchedulerWorkerDelegateImpl::CleanupLockRequired()) had time to exit as
   // they have a raw reference to |this| (and to TaskTracker) which can
   // otherwise result in racy use-after-frees per no longer being part of
-  // |workers_| and hence not being explicitly joined in JoinForTesting() :
-  // https://crbug.com/810464.
+  // |workers_| and hence not being explicitly joined in JoinForTesting():
+  // https://crbug.com/810464. Uses AtomicRefCount to make its only public
+  // method thread-safe.
   TrackedRefFactory<SchedulerWorkerPoolImpl> tracked_ref_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(SchedulerWorkerPoolImpl);
diff --git a/base/task/task_scheduler/scheduler_worker_pool_impl_unittest.cc b/base/task/task_scheduler/scheduler_worker_pool_impl_unittest.cc
index 89c7fbe..71a2391 100644
--- a/base/task/task_scheduler/scheduler_worker_pool_impl_unittest.cc
+++ b/base/task/task_scheduler/scheduler_worker_pool_impl_unittest.cc
@@ -38,6 +38,7 @@
 #include "base/test/bind_test_util.h"
 #include "base/test/gtest_util.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/test/test_timeouts.h"
 #include "base/threading/platform_thread.h"
@@ -75,10 +76,6 @@
       : service_thread_("TaskSchedulerServiceThread"),
         tracked_ref_factory_(this){};
 
-  void CommonSetUp(TimeDelta suggested_reclaim_time = TimeDelta::Max()) {
-    CreateAndStartWorkerPool(suggested_reclaim_time, kMaxTasks);
-  }
-
   void CommonTearDown() {
     service_thread_.Stop();
     task_tracker_.FlushForTesting();
@@ -99,19 +96,23 @@
     mock_scheduler_task_runner_delegate_.SetWorkerPool(worker_pool_.get());
   }
 
-  virtual void StartWorkerPool(TimeDelta suggested_reclaim_time,
-                               size_t max_tasks) {
+  void StartWorkerPool(
+      TimeDelta suggested_reclaim_time,
+      size_t max_tasks,
+      Optional<TimeDelta> may_block_threshold = Optional<TimeDelta>()) {
     ASSERT_TRUE(worker_pool_);
     worker_pool_->Start(
         SchedulerWorkerPoolParams(max_tasks, suggested_reclaim_time), max_tasks,
         service_thread_.task_runner(), nullptr,
-        SchedulerWorkerPoolImpl::WorkerEnvironment::NONE);
+        SchedulerWorkerPoolImpl::WorkerEnvironment::NONE, may_block_threshold);
   }
 
-  void CreateAndStartWorkerPool(TimeDelta suggested_reclaim_time,
-                                size_t max_tasks) {
+  void CreateAndStartWorkerPool(
+      TimeDelta suggested_reclaim_time = TimeDelta::Max(),
+      size_t max_tasks = kMaxTasks,
+      Optional<TimeDelta> may_block_threshold = Optional<TimeDelta>()) {
     CreateWorkerPool();
-    StartWorkerPool(suggested_reclaim_time, max_tasks);
+    StartWorkerPool(suggested_reclaim_time, max_tasks, may_block_threshold);
   }
 
   Thread service_thread_;
@@ -138,7 +139,7 @@
  protected:
   TaskSchedulerWorkerPoolImplTest() = default;
 
-  void SetUp() override { TaskSchedulerWorkerPoolImplTestBase::CommonSetUp(); }
+  void SetUp() override { CreateAndStartWorkerPool(); }
 
   void TearDown() override {
     TaskSchedulerWorkerPoolImplTestBase::CommonTearDown();
@@ -154,7 +155,7 @@
  protected:
   TaskSchedulerWorkerPoolImplTestParam() = default;
 
-  void SetUp() override { TaskSchedulerWorkerPoolImplTestBase::CommonSetUp(); }
+  void SetUp() override { CreateAndStartWorkerPool(); }
 
   void TearDown() override {
     TaskSchedulerWorkerPoolImplTestBase::CommonTearDown();
@@ -330,22 +331,19 @@
  protected:
   TaskSchedulerWorkerPoolImplTestCOMMTAParam() = default;
 
-  void SetUp() override { TaskSchedulerWorkerPoolImplTestBase::CommonSetUp(); }
+  void SetUp() override {
+    CreateWorkerPool();
+    ASSERT_TRUE(worker_pool_);
+    worker_pool_->Start(SchedulerWorkerPoolParams(kMaxTasks, TimeDelta::Max()),
+                        kMaxTasks, service_thread_.task_runner(), nullptr,
+                        SchedulerWorkerPoolImpl::WorkerEnvironment::COM_MTA);
+  }
 
   void TearDown() override {
     TaskSchedulerWorkerPoolImplTestBase::CommonTearDown();
   }
 
  private:
-  void StartWorkerPool(TimeDelta suggested_reclaim_time,
-                       size_t max_tasks) override {
-    ASSERT_TRUE(worker_pool_);
-    worker_pool_->Start(
-        SchedulerWorkerPoolParams(max_tasks, suggested_reclaim_time), max_tasks,
-        service_thread_.task_runner(), nullptr,
-        SchedulerWorkerPoolImpl::WorkerEnvironment::COM_MTA);
-  }
-
   DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerPoolImplTestCOMMTAParam);
 };
 
@@ -805,8 +803,7 @@
   TaskSchedulerWorkerPoolStandbyPolicyTest() = default;
 
   void SetUp() override {
-    TaskSchedulerWorkerPoolImplTestBase::CommonSetUp(
-        kReclaimTimeForCleanupTests);
+    CreateAndStartWorkerPool(kReclaimTimeForCleanupTests);
   }
 
   void TearDown() override {
@@ -1014,13 +1011,6 @@
     return str;
   }
 
-  void SetUp() override {
-    TaskSchedulerWorkerPoolImplTestBase::CommonSetUp();
-    task_runner_ =
-        test::CreateTaskRunnerWithTraits({MayBlock(), WithBaseSyncPrimitives()},
-                                         &mock_scheduler_task_runner_delegate_);
-  }
-
   void TearDown() override {
     TaskSchedulerWorkerPoolImplTestBase::CommonTearDown();
   }
@@ -1078,7 +1068,9 @@
   // Unblocks tasks posted by SaturateWithBlockingTasks().
   void UnblockTasks() { blocking_threads_continue_.Signal(); }
 
-  scoped_refptr<TaskRunner> task_runner_;
+  const scoped_refptr<TaskRunner> task_runner_ =
+      test::CreateTaskRunnerWithTraits({MayBlock(), WithBaseSyncPrimitives()},
+                                       &mock_scheduler_task_runner_delegate_);
 
  private:
   WaitableEvent blocking_threads_running_;
@@ -1091,6 +1083,8 @@
 // worker if needed. Also verify that BlockingScopeExited() decreases max tasks
 // after an increase.
 TEST_P(TaskSchedulerWorkerPoolBlockingTest, ThreadBlockedUnblocked) {
+  CreateAndStartWorkerPool();
+
   ASSERT_EQ(worker_pool_->GetMaxTasksForTesting(), kMaxTasks);
 
   SaturateWithBlockingTasks(GetParam());
@@ -1110,6 +1104,8 @@
 // Verify that tasks posted in a saturated pool before a ScopedBlockingCall will
 // execute after ScopedBlockingCall is instantiated.
 TEST_P(TaskSchedulerWorkerPoolBlockingTest, PostBeforeBlocking) {
+  CreateAndStartWorkerPool();
+
   WaitableEvent thread_running(WaitableEvent::ResetPolicy::AUTOMATIC);
   WaitableEvent thread_can_block;
   WaitableEvent threads_continue;
@@ -1173,6 +1169,8 @@
 // Verify that workers become idle when the pool is over-capacity and that
 // those workers do no work.
 TEST_P(TaskSchedulerWorkerPoolBlockingTest, WorkersIdleWhenOverCapacity) {
+  CreateAndStartWorkerPool();
+
   ASSERT_EQ(worker_pool_->GetMaxTasksForTesting(), kMaxTasks);
 
   SaturateWithBlockingTasks(GetParam());
@@ -1261,18 +1259,22 @@
     TaskSchedulerWorkerPoolBlockingTest::ParamInfoToString);
 
 // Verify that if a thread enters the scope of a MAY_BLOCK ScopedBlockingCall,
-// but exits the scope before the MayBlockThreshold() is reached, that the max
+// but exits the scope before the MayBlock threshold is reached, that the max
 // tasks does not increase.
 TEST_F(TaskSchedulerWorkerPoolBlockingTest, ThreadBlockUnblockPremature) {
+  // Create a pool with an infinite MayBlock threshold so that a MAY_BLOCK
+  // ScopedBlockingCall never increases the max tasks.
+  CreateAndStartWorkerPool(TimeDelta::Max(),  // |suggested_reclaim_time|
+                           kMaxTasks,         // |max_tasks|
+                           TimeDelta::Max()   // |may_block_threshold|
+  );
   ASSERT_EQ(worker_pool_->GetMaxTasksForTesting(), kMaxTasks);
 
-  TimeDelta max_tasks_change_sleep = GetMaxTasksChangeSleepTime();
-  worker_pool_->MaximizeMayBlockThresholdForTesting();
-
   SaturateWithBlockingTasks(NestedBlockingType(BlockingType::MAY_BLOCK,
                                                OptionalBlockingType::NO_BLOCK,
                                                BlockingType::MAY_BLOCK));
-  PlatformThread::Sleep(max_tasks_change_sleep);
+  PlatformThread::Sleep(2 * TimeDelta::FromMicroseconds(
+                                kBlockedWorkersPollMicrosecondsParam.Get()));
   EXPECT_EQ(worker_pool_->NumberOfWorkersForTesting(), kMaxTasks);
   EXPECT_EQ(worker_pool_->GetMaxTasksForTesting(), kMaxTasks);
 
@@ -1286,6 +1288,8 @@
 // WILL_BLOCK ScopedBlockingCall.
 TEST_F(TaskSchedulerWorkerPoolBlockingTest,
        MayBlockIncreaseCapacityNestedWillBlock) {
+  CreateAndStartWorkerPool();
+
   ASSERT_EQ(worker_pool_->GetMaxTasksForTesting(), kMaxTasks);
   auto task_runner =
       test::CreateTaskRunnerWithTraits({MayBlock(), WithBaseSyncPrimitives()},
@@ -1442,6 +1446,8 @@
 // Verify that the maximum number of workers is 256 and that hitting the max
 // leaves the pool in a valid state with regards to max tasks.
 TEST_F(TaskSchedulerWorkerPoolBlockingTest, MaximumWorkersTest) {
+  CreateAndStartWorkerPool();
+
   constexpr size_t kMaxNumberOfWorkers = 256;
   constexpr size_t kNumExtraTasks = 10;
 
diff --git a/build/android/gyp/assert_static_initializers.py b/build/android/gyp/assert_static_initializers.py
index 59ab6f49..717861b7 100755
--- a/build/android/gyp/assert_static_initializers.py
+++ b/build/android/gyp/assert_static_initializers.py
@@ -28,7 +28,7 @@
   args = parser.parse_args()
 
   #TODO(crbug.com/838414): add support for files included via loadable_modules.
-  ignored_libs = ['libarcore_sdk_c_minimal.so']
+  ignored_libs = ['libarcore_sdk_c.so']
 
   si_count = resource_sizes.AnalyzeStaticInitializers(
       args.apk, args.tool_prefix, False, '.', ignored_libs)
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn
index 10f2fc8..49d2e57e 100644
--- a/build/config/BUILD.gn
+++ b/build/config/BUILD.gn
@@ -15,8 +15,8 @@
 # .gn config, but those arguments are only used on macOS. Including
 # mac_sdk_overrides.gni insures that this doesn't trigger an unused argument
 # warning.
-import("//build/config/mac/mac_sdk_overrides.gni")
 import("//build/config/ios/ios_sdk_overrides.gni")
+import("//build/config/mac/mac_sdk_overrides.gni")
 
 import("//build/config/pch.gni")
 import("//build/config/sanitizers/sanitizers.gni")
@@ -221,7 +221,6 @@
       "odbc32.lib",
       "odbccp32.lib",
       "oleaut32.lib",
-      "psapi.lib",
       "shell32.lib",
       "shlwapi.lib",
       "user32.lib",
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index 805818ea0..995638ad 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -247,7 +247,7 @@
     "_ATL_NO_OPENGL",
     "_WINDOWS",
     "CERT_CHAIN_PARA_HAS_EXTRA_FIELDS",
-    "PSAPI_VERSION=1",
+    "PSAPI_VERSION=2",
     "WIN32",
     "_SECURE_ATL",
   ]
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index cc56651..1af78ae 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -1196,11 +1196,14 @@
       "  element_id: %s\n"
       "  bounds: %s\n"
       "  position: %s\n"
+      "  offset_to_transform_parent: %s\n"
       "  scrollable: %d\n"
       "  property tree indices: transform(%d) clip(%d) effect(%d) scroll(%d)\n",
       id(), element_id().ToString().c_str(), bounds().ToString().c_str(),
-      position().ToString().c_str(), scrollable(), transform_tree_index(),
-      clip_tree_index(), effect_tree_index(), scroll_tree_index());
+      position().ToString().c_str(),
+      offset_to_transform_parent().ToString().c_str(), scrollable(),
+      transform_tree_index(), clip_tree_index(), effect_tree_index(),
+      scroll_tree_index());
 }
 
 void Layer::SetUseParentBackfaceVisibility(bool use) {
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 62b79d3..052e9b7 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -69,6 +69,9 @@
     "min_sdk_version=16",
     "target_sdk_version=$android_sdk_version",
   ]
+
+  # ARCore is supported only on monochrome - disable.
+  variables += [ "include_arcore_manifest_flag=false" ]
 }
 
 jinja_template("chrome_modern_public_android_manifest") {
@@ -79,6 +82,9 @@
     "min_sdk_version=21",
     "target_sdk_version=$android_sdk_version",
   ]
+
+  # ARCore is supported only on monochrome - disable.
+  variables += [ "include_arcore_manifest_flag=false" ]
 }
 
 jinja_template("monochrome_public_apk_android_manifest") {
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 3cb29d4..4a7ceea 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -32,7 +32,7 @@
 default_chrome_public_jinja_variables = [
   "channel=$android_channel",
   "enable_vr=$enable_vr",
-  "include_arcore_manifest_flag=$enable_arcore",
+  "include_arcore_manifest_flag=$package_arcore",
 ]
 
 if (android_64bit_browser) {
@@ -376,19 +376,17 @@
       deps += [ "//chrome/browser/android/vr:java" ]
     }
 
-    if (invoker.target_type == "android_apk" || !modularize_ar) {
-      if (enable_arcore) {
-        deps += [ "//third_party/arcore-android-sdk:libdynamite_client_java" ]
-      }
-      if (package_arcore) {
-        # We store this as a separate .so in the APK and only load as needed.
-        if (android_64bit_target_cpu && build_apk_secondary_abi) {
-          secondary_abi_loadable_modules = [ "//third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so" ]
-        } else if (android_64bit_target_cpu && !build_apk_secondary_abi) {
-          loadable_modules = [ "//third_party/arcore-android-sdk/libraries/android_arm64/libarcore_sdk_c_minimal.so" ]
-        } else {
-          loadable_modules = [ "//third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so" ]
-        }
+    if ((invoker.target_type == "android_apk" || !modularize_ar) &&
+        package_arcore) {
+      deps += [ "//third_party/android_deps:com_google_ar_core_java" ]
+
+      # We store this as a separate .so in the APK and only load as needed.
+      if (android_64bit_target_cpu && build_apk_secondary_abi) {
+        secondary_abi_loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
+      } else if (android_64bit_target_cpu && !build_apk_secondary_abi) {
+        loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
+      } else {
+        loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
       }
     }
   }
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 9ecd3b90..7c62de1 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -169,11 +169,14 @@
         <!-- ARCore APK integration -->
         <!-- This tag indicates that this application optionally uses ARCore. -->
         <meta-data android:name="com.google.ar.core" android:value="optional" />
-        <!-- This value referes to ARCore 1.1.
-             This value should be updated when ARCore features require
-             a newer version of the ARCore SDK. -->
+        <!-- This value must match value present in ARCore SDK's .aar -->
+        <!-- TODO(https://crbug.com/917406): modify build scripts to
+             automatically pull this value in - the problem exists because in
+             bundle mode, the ARCore SDK is packaged into AR module and
+             the module installation will not automatically bring in DFM's
+             manifest entries. -->
         <meta-data android:name="com.google.ar.core.min_apk_version"
-            android:value="180226000"/>
+            android:value="180815000"/>
         {% endif %}
 
         <!-- Cast support -->
diff --git a/chrome/android/java/res/xml/sync_and_services_preferences.xml b/chrome/android/java/res/xml/sync_and_services_preferences.xml
index 13654aa..fd8495e 100644
--- a/chrome/android/java/res/xml/sync_and_services_preferences.xml
+++ b/chrome/android/java/res/xml/sync_and_services_preferences.xml
@@ -85,34 +85,37 @@
         android:title="@string/prefs_nonpersonalized_services_section_title"
         android:summary="@string/prefs_nonpersonalized_services_section_summary">
 
-        <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference
+        <org.chromium.chrome.browser.preferences.ChromeSwitchPreference
             android:key="search_suggestions"
             android:title="@string/autocomplete_searches_and_urls_title"
             android:summary="@string/autocomplete_searches_and_urls_summary"
-            android:defaultValue="true"/>
-        <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference
+            android:persistent="false"/>
+        <org.chromium.chrome.browser.preferences.ChromeSwitchPreference
             android:key="network_predictions"
             android:title="@string/preload_pages_title"
             android:summary="@string/preload_pages_summary"
             android:persistent="false"/>
-        <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference
+        <org.chromium.chrome.browser.preferences.ChromeSwitchPreference
             android:key="navigation_error"
             android:title="@string/navigation_error_suggestions_title"
             android:summary="@string/navigation_error_suggestions_summary"
-            android:defaultValue="true"/>
-        <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference
+            android:persistent="false"/>
+        <org.chromium.chrome.browser.preferences.ChromeSwitchPreference
             android:key="safe_browsing"
             android:title="@string/safe_browsing_title"
-            android:summary="@string/safe_browsing_summary"/>
-        <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference
+            android:summary="@string/safe_browsing_summary"
+            android:persistent="false"/>
+        <org.chromium.chrome.browser.preferences.ChromeSwitchPreference
             android:key="safe_browsing_scout_reporting"
             android:title="@string/safe_browsing_scout_reporting_title"
-            android:summary="@string/safe_browsing_scout_reporting_summary"/>
-        <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference
+            android:summary="@string/safe_browsing_scout_reporting_summary"
+            android:persistent="false"/>
+        <org.chromium.chrome.browser.preferences.ChromeSwitchPreference
             android:key="usage_and_crash_reports"
             android:title="@string/usage_and_crash_reports_title"
-            android:summary="@string/usage_and_crash_reports_summary"/>
-        <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference
+            android:summary="@string/usage_and_crash_reports_summary"
+            android:persistent="false"/>
+        <org.chromium.chrome.browser.preferences.ChromeSwitchPreference
             android:key="url_keyed_anonymized_data"
             android:title="@string/url_keyed_anonymized_data_title"
             android:summary="@string/url_keyed_anonymized_data_summary"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
index 53f5d33..650fada91 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
@@ -239,7 +239,8 @@
                 // since we do not need to show default icon then change it to favicon. It is ok to
                 // wait here since the favicon is loaded from local cache in favicon service sql
                 // database.
-                if (mCurrentMediaImage == null && !fetchFaviconImage()) {
+                // Incognito Tabs need the default icon as they don't show the media icon.
+                if (mTab.isIncognito() || (mCurrentMediaImage == null && !fetchFaviconImage())) {
                     mNotificationInfoBuilder.setDefaultNotificationLargeIcon(
                             R.drawable.audio_playing_square);
                 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
index cb4f100f..d33fcf1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
@@ -159,13 +159,13 @@
     private @Nullable Preference mContextualSuggestions;
 
     private SigninExpandablePreferenceGroup mNonpersonalizedServices;
-    private ChromeBaseCheckBoxPreference mSearchSuggestions;
-    private ChromeBaseCheckBoxPreference mNetworkPredictions;
-    private ChromeBaseCheckBoxPreference mNavigationError;
-    private ChromeBaseCheckBoxPreference mSafeBrowsing;
-    private ChromeBaseCheckBoxPreference mSafeBrowsingReporting;
-    private ChromeBaseCheckBoxPreference mUsageAndCrashReporting;
-    private ChromeBaseCheckBoxPreference mUrlKeyedAnonymizedData;
+    private ChromeSwitchPreference mSearchSuggestions;
+    private ChromeSwitchPreference mNetworkPredictions;
+    private ChromeSwitchPreference mNavigationError;
+    private ChromeSwitchPreference mSafeBrowsing;
+    private ChromeSwitchPreference mSafeBrowsingReporting;
+    private ChromeSwitchPreference mUsageAndCrashReporting;
+    private ChromeSwitchPreference mUrlKeyedAnonymizedData;
     private @Nullable Preference mContextualSearch;
 
     private boolean mIsEngineInitialized;
@@ -237,35 +237,34 @@
             type.setOnPreferenceChangeListener(this);
         }
 
-        mSearchSuggestions = (ChromeBaseCheckBoxPreference) findPreference(PREF_SEARCH_SUGGESTIONS);
+        mSearchSuggestions = (ChromeSwitchPreference) findPreference(PREF_SEARCH_SUGGESTIONS);
         mSearchSuggestions.setOnPreferenceChangeListener(this);
         mSearchSuggestions.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
 
-        mNetworkPredictions =
-                (ChromeBaseCheckBoxPreference) findPreference(PREF_NETWORK_PREDICTIONS);
+        mNetworkPredictions = (ChromeSwitchPreference) findPreference(PREF_NETWORK_PREDICTIONS);
         mNetworkPredictions.setOnPreferenceChangeListener(this);
         mNetworkPredictions.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
 
-        mNavigationError = (ChromeBaseCheckBoxPreference) findPreference(PREF_NAVIGATION_ERROR);
+        mNavigationError = (ChromeSwitchPreference) findPreference(PREF_NAVIGATION_ERROR);
         mNavigationError.setOnPreferenceChangeListener(this);
         mNavigationError.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
 
-        mSafeBrowsing = (ChromeBaseCheckBoxPreference) findPreference(PREF_SAFE_BROWSING);
+        mSafeBrowsing = (ChromeSwitchPreference) findPreference(PREF_SAFE_BROWSING);
         mSafeBrowsing.setOnPreferenceChangeListener(this);
         mSafeBrowsing.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
 
         mSafeBrowsingReporting =
-                (ChromeBaseCheckBoxPreference) findPreference(PREF_SAFE_BROWSING_SCOUT_REPORTING);
+                (ChromeSwitchPreference) findPreference(PREF_SAFE_BROWSING_SCOUT_REPORTING);
         mSafeBrowsingReporting.setOnPreferenceChangeListener(this);
         mSafeBrowsingReporting.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
 
         mUsageAndCrashReporting =
-                (ChromeBaseCheckBoxPreference) findPreference(PREF_USAGE_AND_CRASH_REPORTING);
+                (ChromeSwitchPreference) findPreference(PREF_USAGE_AND_CRASH_REPORTING);
         mUsageAndCrashReporting.setOnPreferenceChangeListener(this);
         mUsageAndCrashReporting.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
 
         mUrlKeyedAnonymizedData =
-                (ChromeBaseCheckBoxPreference) findPreference(PREF_URL_KEYED_ANONYMIZED_DATA);
+                (ChromeSwitchPreference) findPreference(PREF_URL_KEYED_ANONYMIZED_DATA);
         mUrlKeyedAnonymizedData.setOnPreferenceChangeListener(this);
         mUrlKeyedAnonymizedData.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
index 593ff30..aac33c1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
@@ -90,7 +90,7 @@
     private static String getArCoreShimLibraryPath() {
         try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
             return ((BaseDexClassLoader) ContextUtils.getApplicationContext().getClassLoader())
-                    .findLibrary("arcore_sdk_c_minimal");
+                    .findLibrary("arcore_sdk_c");
         }
     }
 
@@ -203,6 +203,7 @@
                 break;
         }
 
+        // TODO(https://crbug.com/916651) - use ARCore SDK's InstallActivity to install ARCore
         SimpleConfirmInfoBarBuilder.Listener listener = new SimpleConfirmInfoBarBuilder.Listener() {
             @Override
             public void onInfoBarDismissed() {
@@ -228,7 +229,7 @@
     private boolean shouldRequestInstallArModule() {
         try {
             // Try to find class in AR module that has not been obfuscated.
-            Class.forName("com.google.vr.dynamite.client.UsedByNative");
+            Class.forName("com.google.ar.core.ArCoreApk");
             return false;
         } catch (ClassNotFoundException e) {
             return true;
diff --git a/chrome/android/modules/ar/AndroidManifest.xml b/chrome/android/modules/ar/AndroidManifest.xml
index 46151b6..19f6631 100644
--- a/chrome/android/modules/ar/AndroidManifest.xml
+++ b/chrome/android/modules/ar/AndroidManifest.xml
@@ -19,5 +19,7 @@
     </dist:module>
 
     <application>
+        <!-- This tag indicates that this application optionally uses ARCore. -->
+        <meta-data android:name="com.google.ar.core" android:value="optional" />
     </application>
 </manifest>
diff --git a/chrome/android/modules/ar/ar_module_tmpl.gni b/chrome/android/modules/ar/ar_module_tmpl.gni
index 8c156b9..4123ffd 100644
--- a/chrome/android/modules/ar/ar_module_tmpl.gni
+++ b/chrome/android/modules/ar/ar_module_tmpl.gni
@@ -35,23 +35,23 @@
     android_manifest = _manifest
     android_manifest_dep = ":$_manifest_target"
     deps = [
-      "//third_party/arcore-android-sdk:libdynamite_client_java",
+      "//third_party/android_deps:com_google_ar_core_java",
     ]
 
     # We only want to add the 32 bit arcore shim even for 64 bit monochrome
     # builds. AR is never used in 64 bit mode. We store the arcore shim as a
     # separate .so in the bundle module and only load as needed.
     if (android_64bit_target_cpu && build_apk_secondary_abi) {
-      secondary_abi_loadable_modules = [ "//third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so" ]
+      secondary_abi_loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
 
       # Disguise 32 bit library as 64 bit. This works around a Play Core bug where only 64 bit
       # libraries are extracted on 64 bit devices.
       # TODO(crbug.com/902859): Remove once bug is fixed.
-      loadable_modules = [ "//third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so" ]
+      loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
     } else if (android_64bit_target_cpu && !build_apk_secondary_abi) {
-      loadable_modules = [ "//third_party/arcore-android-sdk/libraries/android_arm64/libarcore_sdk_c_minimal.so" ]
+      loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
     } else {
-      loadable_modules = [ "//third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so" ]
+      loadable_modules = [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
     }
     uncompress_shared_libraries = true
 
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index b7b9047..e0f2e71 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-73.0.3663.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-73.0.3664.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/browser/android/vr/arcore_device/arcore_impl.cc b/chrome/browser/android/vr/arcore_device/arcore_impl.cc
index 9d9a1d3a..5ddb02e9 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_impl.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_impl.cc
@@ -62,13 +62,6 @@
     return false;
   }
 
-  // We just use the default config.
-  status = ArSession_checkSupported(session.get(), arcore_config.get());
-  if (status != AR_SUCCESS) {
-    DLOG(ERROR) << "ArSession_checkSupported failed: " << status;
-    return false;
-  }
-
   status = ArSession_configure(session.get(), arcore_config.get());
   if (status != AR_SUCCESS) {
     DLOG(ERROR) << "ArSession_configure failed: " << status;
diff --git a/chrome/browser/android/vr/arcore_device/arcore_shim.cc b/chrome/browser/android/vr/arcore_device/arcore_shim.cc
index 76edce51..98a009875 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_shim.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_shim.cc
@@ -35,7 +35,6 @@
   CALL(ArPose_destroy)                   \
   CALL(ArPose_getMatrix)                 \
   CALL(ArPose_getPoseRaw)                \
-  CALL(ArSession_checkSupported)         \
   CALL(ArSession_configure)              \
   CALL(ArSession_create)                 \
   CALL(ArSession_destroy)                \
@@ -79,13 +78,13 @@
   if (!sdk_handle) {
     char* error_string = nullptr;
     error_string = dlerror();
-    LOG(ERROR) << "Could not open libarcore_sdk_c_minimal.so: " << error_string;
+    LOG(ERROR) << "Could not open libarcore_sdk_c.so: " << error_string;
     return false;
   } else {
     VLOG(2) << "Opened shim shared library.";
   }
 
-  // TODO(vollick): check SDK version.
+  // TODO(https://crbug.com/914999): check SDK version.
   arcore_api = new ArCoreApi();
 
 #define CALL(fn) LoadFunction(sdk_handle, #fn, &arcore_api->impl_##fn);
@@ -256,11 +255,6 @@
   arcore_api->impl_ArPose_getPoseRaw(session, pose, out_pose_raw);
 }
 
-ArStatus ArSession_checkSupported(const ArSession* session,
-                                  const ArConfig* config) {
-  return arcore_api->impl_ArSession_checkSupported(session, config);
-}
-
 ArStatus ArSession_configure(ArSession* session, const ArConfig* config) {
   return arcore_api->impl_ArSession_configure(session, config);
 }
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc
index 80d3c08..6c85224 100644
--- a/chrome/browser/autofill/autofill_browsertest.cc
+++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -142,7 +142,7 @@
   // The function returns after the PersonalDataManager is updated.
   void FillFormAndSubmit(const std::string& filename, const FormMap& data) {
     FillFormAndSubmitWithHandler(filename, data, kDocumentClickHandlerSubmitJS,
-                                 true, true);
+                                 true);
   }
 
   // Helper where the actual submit JS code can be specified, as well as whether
@@ -150,16 +150,13 @@
   void FillFormAndSubmitWithHandler(const std::string& filename,
                                     const FormMap& data,
                                     const std::string& submit_js,
-                                    bool simulate_click,
-                                    bool expect_personal_data_change) {
+                                    bool simulate_click) {
     GURL url = embedded_test_server()->GetURL("/autofill/" + filename);
     NavigateParams params(browser(), url, ui::PAGE_TRANSITION_LINK);
     params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
     ui_test_utils::NavigateToURL(&params);
 
-    std::unique_ptr<WindowedPersonalDataManagerObserver> observer;
-    if (expect_personal_data_change)
-      observer.reset(new WindowedPersonalDataManagerObserver(browser()));
+    WindowedPersonalDataManagerObserver observer(browser());
 
     std::string js = GetJSToFillForm(data) + submit_js;
     ASSERT_TRUE(content::ExecuteScript(web_contents(), js));
@@ -170,11 +167,7 @@
           browser()->tab_strip_model()->GetActiveWebContents(), 0,
           blink::WebMouseEvent::Button::kLeft);
     }
-    // We may not always be expecting changes in Personal data.
-    if (observer.get())
-      observer->Wait();
-    else
-      base::RunLoop().RunUntilIdle();
+    observer.Wait();
   }
 
   // Aggregate profiles from forms into Autofill preferences. Returns the number
@@ -255,7 +248,7 @@
 
   std::string submit("document.forms[0].submit();");
   FillFormAndSubmitWithHandler("duplicate_profiles_test.html", data, submit,
-                               false, true);
+                               false);
 
   ASSERT_EQ(1u, personal_data_manager()->GetProfiles().size());
 }
@@ -276,7 +269,7 @@
       "document.forms[0].addEventListener('submit', preventFunction);"
       "document.querySelector('input[type=submit]').click();");
   FillFormAndSubmitWithHandler("duplicate_profiles_test.html", data, submit,
-                               false, false);
+                               false);
 
   // The AutofillManager will update the user's profile.
   EXPECT_EQ(1u, personal_data_manager()->GetProfiles().size());
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc
index 8bad9d8..623342f 100644
--- a/chrome/browser/autofill/autofill_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -1209,18 +1209,7 @@
 
 // Test that an input field is not rendered with the yellow autofilled
 // background color when choosing an option from the datalist suggestion list.
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS) || defined(OS_WIN) || \
-    defined(OS_LINUX)
-// Flakily triggers and assert on Mac; flakily gets empty string instead
-// of "Adam" on ChromeOS.
-// http://crbug.com/419868, http://crbug.com/595385.
-// Flaky on Windows and Linux as well: http://crbug.com/595385
-#define MAYBE_OnSelectOptionFromDatalist DISABLED_OnSelectOptionFromDatalist
-#else
-#define MAYBE_OnSelectOptionFromDatalist OnSelectOptionFromDatalist
-#endif
-IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest,
-                       MAYBE_OnSelectOptionFromDatalist) {
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, OnSelectOptionFromDatalist) {
   static const char kTestForm[] =
       "<form action=\"http://www.example.com/\" method=\"POST\">"
       "  <input list=\"dl\" type=\"search\" id=\"firstname\"><br>"
@@ -1244,7 +1233,9 @@
                        {ObservedUiEvents::kSuggestionShown});
   SendKeyToDataListPopup(ui::DomKey::ARROW_DOWN);
   SendKeyToDataListPopup(ui::DomKey::ENTER);
-  ExpectFieldValue("firstname", "Adam");
+  // Pressing the down arrow preselects the first item. Pressing it again
+  // selects the second item.
+  ExpectFieldValue("firstname", "Bob");
   std::string color;
   GetFieldBackgroundColor("firstname", &color);
   EXPECT_EQ(color, orginalcolor);
diff --git a/chrome/browser/browser_switcher/browser_switcher_navigation_throttle_unittest.cc b/chrome/browser/browser_switcher/browser_switcher_navigation_throttle_unittest.cc
index 1350390..395a284 100644
--- a/chrome/browser/browser_switcher/browser_switcher_navigation_throttle_unittest.cc
+++ b/chrome/browser/browser_switcher/browser_switcher_navigation_throttle_unittest.cc
@@ -13,16 +13,16 @@
 #include "chrome/browser/browser_switcher/ieem_sitelist_parser.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/navigation_throttle.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
+using content::MockNavigationHandle;
 using content::NavigationThrottle;
-using content::NavigationHandle;
 
 using ::testing::Return;
 using ::testing::_;
@@ -49,22 +49,6 @@
   MOCK_METHOD1(SetExternalSitelist, void(ParsedXml&&));
 };
 
-class MockBrowserClient : public content::ContentBrowserClient {
- public:
-  MockBrowserClient() = default;
-  ~MockBrowserClient() override = default;
-
-  // Only construct a BrowserSwitcherNavigationThrottle so that we can test it
-  // in isolation.
-  std::vector<std::unique_ptr<NavigationThrottle>> CreateThrottlesForNavigation(
-      NavigationHandle* handle) override {
-    std::vector<std::unique_ptr<NavigationThrottle>> throttles;
-    throttles.push_back(
-        BrowserSwitcherNavigationThrottle::MaybeCreateThrottleFor(handle));
-    return throttles;
-  }
-};
-
 }  // namespace
 
 class BrowserSwitcherNavigationThrottleTest
@@ -74,7 +58,6 @@
 
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
-    original_client_ = content::SetBrowserClientForTesting(&client_);
 
     BrowserSwitcherService* service =
         BrowserSwitcherServiceFactory::GetForBrowserContext(
@@ -91,41 +74,42 @@
     service->SetSitelistForTesting(std::move(sitelist));
   }
 
-  void TearDown() override {
-    content::SetBrowserClientForTesting(original_client_);
-    ChromeRenderViewHostTestHarness::TearDown();
+  std::unique_ptr<MockNavigationHandle> CreateMockNavigationHandle(
+      const GURL& url) {
+    return std::make_unique<MockNavigationHandle>(url, main_rfh());
   }
 
-  std::unique_ptr<NavigationHandle> CreateNavigationHandle(const GURL& url) {
-    return NavigationHandle::CreateNavigationHandleForTesting(url, main_rfh());
+  std::unique_ptr<NavigationThrottle> CreateNavigationThrottle(
+      content::NavigationHandle* handle) {
+    return BrowserSwitcherNavigationThrottle::MaybeCreateThrottleFor(handle);
   }
 
   MockAlternativeBrowserLauncher* launcher() { return launcher_; }
   MockBrowserSwitcherSitelist* sitelist() { return sitelist_; }
 
  private:
-  MockBrowserClient client_;
-  content::ContentBrowserClient* original_client_;
-
   MockAlternativeBrowserLauncher* launcher_;
   MockBrowserSwitcherSitelist* sitelist_;
 };
 
 TEST_F(BrowserSwitcherNavigationThrottleTest, ShouldIgnoreNavigation) {
   EXPECT_CALL(*sitelist(), ShouldSwitch(_)).WillOnce(Return(false));
-  std::unique_ptr<NavigationHandle> handle =
-      CreateNavigationHandle(GURL("https://example.com/"));
-  EXPECT_EQ(NavigationThrottle::PROCEED,
-            handle->CallWillStartRequestForTesting());
+  std::unique_ptr<MockNavigationHandle> handle =
+      CreateMockNavigationHandle(GURL("https://example.com/"));
+  std::unique_ptr<NavigationThrottle> throttle =
+      CreateNavigationThrottle(handle.get());
+  EXPECT_EQ(NavigationThrottle::PROCEED, throttle->WillStartRequest());
 }
 
 TEST_F(BrowserSwitcherNavigationThrottleTest, LaunchesOnStartRequest) {
   EXPECT_CALL(*sitelist(), ShouldSwitch(_)).WillOnce(Return(true));
   EXPECT_CALL(*launcher(), Launch(_)).WillOnce(Return(true));
-  std::unique_ptr<NavigationHandle> handle =
-      CreateNavigationHandle(GURL("https://example.com/"));
+  std::unique_ptr<MockNavigationHandle> handle =
+      CreateMockNavigationHandle(GURL("https://example.com/"));
+  std::unique_ptr<NavigationThrottle> throttle =
+      CreateNavigationThrottle(handle.get());
   EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE,
-            handle->CallWillStartRequestForTesting());
+            throttle->WillStartRequest());
   base::RunLoop().RunUntilIdle();
 }
 
@@ -134,25 +118,25 @@
       .WillOnce(Return(false))
       .WillOnce(Return(true));
   EXPECT_CALL(*launcher(), Launch(_)).WillOnce(Return(true));
-  std::unique_ptr<NavigationHandle> handle =
-      CreateNavigationHandle(GURL("https://yahoo.com/"));
-  EXPECT_EQ(NavigationThrottle::PROCEED,
-            handle->CallWillStartRequestForTesting());
+  std::unique_ptr<MockNavigationHandle> handle =
+      CreateMockNavigationHandle(GURL("https://yahoo.com/"));
+  std::unique_ptr<NavigationThrottle> throttle =
+      CreateNavigationThrottle(handle.get());
+  EXPECT_EQ(NavigationThrottle::PROCEED, throttle->WillStartRequest());
+  handle->set_url(GURL("https://bing.com/"));
   EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE,
-            handle->CallWillRedirectRequestForTesting(
-                GURL("https://bing.com/"), /* new_method_is_post */ false,
-                GURL("https://yahoo.com/"),
-                /* new_is_external_protocol */ false));
+            throttle->WillRedirectRequest());
   base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(BrowserSwitcherNavigationThrottleTest, FallsBackToLoadingNormally) {
   EXPECT_CALL(*sitelist(), ShouldSwitch(_)).WillOnce(Return(true));
   EXPECT_CALL(*launcher(), Launch(_)).WillOnce(Return(false));
-  std::unique_ptr<NavigationHandle> handle =
-      CreateNavigationHandle(GURL("https://yahoo.com/"));
-  EXPECT_EQ(NavigationThrottle::PROCEED,
-            handle->CallWillStartRequestForTesting());
+  std::unique_ptr<MockNavigationHandle> handle =
+      CreateMockNavigationHandle(GURL("https://yahoo.com/"));
+  std::unique_ptr<NavigationThrottle> throttle =
+      CreateNavigationThrottle(handle.get());
+  EXPECT_EQ(NavigationThrottle::PROCEED, throttle->WillStartRequest());
 }
 
 }  // namespace browser_switcher
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 2b507eb..be047438 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -820,19 +820,32 @@
 
 }  // namespace
 
+ACTION(QuitMainMessageLoop) {
+  base::RunLoop::QuitCurrentWhenIdleDeprecated();
+}
+
+class PersonalDataLoadedObserverMock
+    : public autofill::PersonalDataManagerObserver {
+ public:
+  PersonalDataLoadedObserverMock() {}
+  ~PersonalDataLoadedObserverMock() override {}
+  MOCK_METHOD0(OnPersonalDataChanged, void());
+  MOCK_METHOD0(OnPersonalDataFinishedProfileTasks, void());
+};
+
 // RemoveAutofillTester is not a part of the anonymous namespace above, as
 // PersonalDataManager declares it a friend in an empty namespace.
-class RemoveAutofillTester : public autofill::PersonalDataManagerObserver {
+class RemoveAutofillTester {
  public:
   explicit RemoveAutofillTester(TestingProfile* profile)
       : personal_data_manager_(
             autofill::PersonalDataManagerFactory::GetForProfile(profile)) {
     autofill::test::DisableSystemServices(profile->GetPrefs());
-    personal_data_manager_->AddObserver(this);
+    personal_data_manager_->AddObserver(&personal_data_observer_);
   }
 
-  ~RemoveAutofillTester() override {
-    personal_data_manager_->RemoveObserver(this);
+  ~RemoveAutofillTester() {
+    personal_data_manager_->RemoveObserver(&personal_data_observer_);
     autofill::test::ReenableSystemServices();
   }
 
@@ -880,7 +893,8 @@
     profiles.push_back(profile);
 
     personal_data_manager_->SetProfiles(&profiles);
-    base::TaskScheduler::GetInstance()->FlushForTesting();
+
+    WaitForOnPersonalDataFinishedProfileTasks();
 
     std::vector<autofill::CreditCard> cards;
     autofill::CreditCard card;
@@ -895,15 +909,24 @@
     cards.push_back(card);
 
     personal_data_manager_->SetCreditCards(&cards);
-    base::TaskScheduler::GetInstance()->FlushForTesting();
+    WaitForOnPersonalDataChanged();
   }
 
  private:
-  void OnPersonalDataChanged() override {
-    base::RunLoop::QuitCurrentWhenIdleDeprecated();
+  void WaitForOnPersonalDataChanged() {
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .WillRepeatedly(QuitMainMessageLoop());
+    base::RunLoop().Run();
+  }
+
+  void WaitForOnPersonalDataFinishedProfileTasks() {
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+        .WillRepeatedly(QuitMainMessageLoop());
+    base::RunLoop().Run();
   }
 
   autofill::PersonalDataManager* personal_data_manager_;
+  PersonalDataLoadedObserverMock personal_data_observer_;
   DISALLOW_COPY_AND_ASSIGN(RemoveAutofillTester);
 };
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 9784be9..d964a7e 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2274,23 +2274,22 @@
 void ChromeContentBrowserClient::NavigationRequestStarted(
     int frame_tree_node_id,
     const GURL& url,
-    std::unique_ptr<net::HttpRequestHeaders>* extra_headers,
+    net::HttpRequestHeaders* extra_headers,
     int* extra_load_flags) {
   WebContents* web_contents =
       WebContents::FromFrameTreeNodeId(frame_tree_node_id);
   content::BrowserContext* browser_context = web_contents->GetBrowserContext();
 
-  *extra_headers = ClientHintsFactory::GetForBrowserContext(browser_context)
-                       ->GetAdditionalNavigationRequestClientHintsHeaders(url);
+  ClientHintsFactory::GetForBrowserContext(browser_context)
+      ->GetAdditionalNavigationRequestClientHintsHeaders(url, extra_headers);
+
   prerender::PrerenderContents* prerender_contents =
       prerender::PrerenderContents::FromWebContents(web_contents);
   if (prerender_contents &&
       prerender_contents->prerender_mode() == prerender::PREFETCH_ONLY) {
     *extra_load_flags = net::LOAD_PREFETCH;
-    if (*extra_headers == nullptr)
-      *extra_headers = std::make_unique<net::HttpRequestHeaders>();
-    extra_headers->get()->SetHeader(prerender::kPurposeHeaderName,
-                                    prerender::kPurposeHeaderValue);
+    extra_headers->SetHeader(prerender::kPurposeHeaderName,
+                             prerender::kPurposeHeaderValue);
   }
 
   if (!browser_context->IsOffTheRecord()) {
@@ -2306,7 +2305,7 @@
 void ChromeContentBrowserClient::NavigationRequestRedirected(
     int frame_tree_node_id,
     const GURL& url,
-    base::Optional<net::HttpRequestHeaders>* modified_headers) {
+    net::HttpRequestHeaders* modified_headers) {
   WebContents* web_contents =
       WebContents::FromFrameTreeNodeId(frame_tree_node_id);
   content::BrowserContext* browser_context = web_contents->GetBrowserContext();
@@ -2316,22 +2315,12 @@
     policy::PolicyHeaderService* policy_header_service =
         policy::PolicyHeaderServiceFactory::GetForBrowserContext(
             browser_context);
-    if (policy_header_service) {
-      std::unique_ptr<net::HttpRequestHeaders> extra_headers;
-      policy_header_service->AddPolicyHeaders(url, &extra_headers);
-      if (extra_headers)
-        *modified_headers = std::move(*extra_headers);
-    }
+    if (policy_header_service)
+      policy_header_service->AddPolicyHeaders(url, modified_headers);
   }
 
-  std::unique_ptr<net::HttpRequestHeaders> client_hints_extra_headers =
-      ClientHintsFactory::GetForBrowserContext(browser_context)
-          ->GetAdditionalNavigationRequestClientHintsHeaders(url);
-  if (client_hints_extra_headers) {
-    if (!modified_headers->has_value())
-      *modified_headers = net::HttpRequestHeaders();
-    modified_headers->value().MergeFrom(*client_hints_extra_headers);
-  }
+  ClientHintsFactory::GetForBrowserContext(browser_context)
+      ->GetAdditionalNavigationRequestClientHintsHeaders(url, modified_headers);
 }
 
 bool ChromeContentBrowserClient::AllowAppCache(
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 9e62e44..0d3ac2c6 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -200,15 +200,14 @@
   void UpdateRendererPreferencesForWorker(
       content::BrowserContext* browser_context,
       content::RendererPreferences* out_prefs) override;
-  void NavigationRequestStarted(
-      int frame_tree_node_id,
-      const GURL& url,
-      std::unique_ptr<net::HttpRequestHeaders>* extra_headers,
-      int* extra_load_flags) override;
+  void NavigationRequestStarted(int frame_tree_node_id,
+                                const GURL& url,
+                                net::HttpRequestHeaders* extra_headers,
+                                int* extra_load_flags) override;
   void NavigationRequestRedirected(
       int frame_tree_node_id,
       const GURL& url,
-      base::Optional<net::HttpRequestHeaders>* modified_headers) override;
+      net::HttpRequestHeaders* modified_headers) override;
   bool AllowAppCache(const GURL& manifest_url,
                      const GURL& first_party,
                      content::ResourceContext* context) override;
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc
index 039d6021..3188d94f 100644
--- a/chrome/browser/chrome_navigation_browsertest.cc
+++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -990,7 +990,7 @@
       browser()->tab_strip_model()->GetActiveWebContents();
   const char* kScriptFormat =
       "window.domAutomationController.send(!!window.open('%s'));";
-  GURL popup_url = embedded_test_server()->GetURL("a.com", "/title1.html");
+  GURL popup_url = embedded_test_server()->GetURL("b.com", "/title1.html");
   content::TestNavigationObserver popup_waiter(nullptr, 1);
   popup_waiter.StartWatchingNewWebContents();
   EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
@@ -1013,12 +1013,10 @@
       popup,
       "window.opener.location ='data:html/text;base64,'+btoa('payload');"));
   observer.WaitForFinished();
-  histograms.ExpectUniqueSample(
-      "Navigation.DownloadPolicy",
-      // TODO(csharrison): Update this to avoid using hardcoded number, since
-      // right now NavigationDownloadPolicy is not exposed publicly through
-      // //content.
-      4 /* NavigationDownloadPolicy::kAllowOpenerNoGesture */, 1);
+  histograms.ExpectBucketCount(
+      "Blink.UseCounter.Features",
+      blink::mojom::WebFeature::kOpenerNavigationDownloadCrossOriginNoGesture,
+      1);
 
   // Delete any pending download.
   std::vector<download::DownloadItem*> download_items;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index abce227..d3610f5 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -31,6 +31,7 @@
     "//chromeos:cicerone_proto",
     "//chromeos:concierge_proto",
     "//chromeos:power_manager_proto",
+    "//chromeos:runtime_probe_proto",
     "//chromeos:seneschal_proto",
     "//chromeos:vm_applications_apps_proto",
     "//chromeos/strings",
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index 4c45ccd85..7f14b4d7 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -901,7 +901,8 @@
     return;
   }
   if (!GetCiceroneClient()->IsContainerStartedSignalConnected() ||
-      !GetCiceroneClient()->IsContainerShutdownSignalConnected()) {
+      !GetCiceroneClient()->IsContainerShutdownSignalConnected() ||
+      !GetCiceroneClient()->IsLxdContainerStartingSignalConnected()) {
     LOG(ERROR) << "Async call to StartLxdContainer can't complete when signals "
                   "are not connected.";
     std::move(callback).Run(CrostiniResult::CLIENT_ERROR);
@@ -911,6 +912,7 @@
   request.set_vm_name(std::move(vm_name));
   request.set_container_name(std::move(container_name));
   request.set_owner_id(owner_id_);
+  request.set_async(true);
   GetCiceroneClient()->StartLxdContainer(
       std::move(request),
       base::BindOnce(&CrostiniManager::OnStartLxdContainer,
@@ -1598,21 +1600,37 @@
     CrostiniResultCallback callback,
     base::Optional<vm_tools::cicerone::StartLxdContainerResponse> reply) {
   if (!reply.has_value()) {
-    LOG(ERROR) << "Failed to start lxd container in vm. Empty response.";
+    VLOG(1) << "Failed to start lxd container in vm. Empty response.";
     std::move(callback).Run(CrostiniResult::CONTAINER_START_FAILED);
     return;
   }
   vm_tools::cicerone::StartLxdContainerResponse response = reply.value();
 
-  if (!(response.status() ==
-            vm_tools::cicerone::StartLxdContainerResponse::STARTED ||
-        response.status() ==
-            vm_tools::cicerone::StartLxdContainerResponse::RUNNING)) {
-    LOG(ERROR) << "Failed to start container: " << response.failure_reason();
-    std::move(callback).Run(CrostiniResult::CONTAINER_START_FAILED);
-    return;
+  switch (response.status()) {
+    case vm_tools::cicerone::StartLxdContainerResponse::UNKNOWN:
+    case vm_tools::cicerone::StartLxdContainerResponse::FAILED:
+      LOG(ERROR) << "Failed to start container: " << response.failure_reason();
+      std::move(callback).Run(CrostiniResult::CONTAINER_START_FAILED);
+      break;
+
+    case vm_tools::cicerone::StartLxdContainerResponse::STARTED:
+    case vm_tools::cicerone::StartLxdContainerResponse::RUNNING:
+      std::move(callback).Run(CrostiniResult::SUCCESS);
+      break;
+
+    case vm_tools::cicerone::StartLxdContainerResponse::STARTING:
+    case vm_tools::cicerone::StartLxdContainerResponse::REMAPPING:
+      VLOG(1) << "Awaiting LxdContainerStartingSignal for " << owner_id_ << ", "
+              << vm_name << ", " << container_name;
+      // The callback will be called when we receive the LxdContainerStarting
+      // signal.
+      start_lxd_container_callbacks_.emplace(
+          std::make_tuple(vm_name, container_name), std::move(callback));
+      break;
+    default:
+      NOTREACHED();
+      break;
   }
-  std::move(callback).Run(CrostiniResult::SUCCESS);
 }
 
 void CrostiniManager::OnSetUpLxdContainerUser(
@@ -1705,6 +1723,37 @@
   tremplin_started_callbacks_.erase(range.first, range.second);
 }
 
+void CrostiniManager::OnLxdContainerStarting(
+    const vm_tools::cicerone::LxdContainerStartingSignal& signal) {
+  if (signal.owner_id() != owner_id_)
+    return;
+  CrostiniResult result;
+
+  switch (signal.status()) {
+    case vm_tools::cicerone::LxdContainerStartingSignal::UNKNOWN:
+      result = CrostiniResult::UNKNOWN_ERROR;
+      break;
+    case vm_tools::cicerone::LxdContainerStartingSignal::CANCELLED:
+      result = CrostiniResult::CONTAINER_START_CANCELLED;
+      break;
+    case vm_tools::cicerone::LxdContainerStartingSignal::STARTED:
+      result = CrostiniResult::SUCCESS;
+      break;
+    case vm_tools::cicerone::LxdContainerStartingSignal::FAILED:
+      result = CrostiniResult::CONTAINER_START_FAILED;
+      break;
+    default:
+      result = CrostiniResult::UNKNOWN_ERROR;
+      break;
+  }
+  // Find the callbacks to call, then erase them from the map.
+  auto range = start_lxd_container_callbacks_.equal_range(
+      std::make_tuple(signal.vm_name(), signal.container_name()));
+  for (auto it = range.first; it != range.second; ++it) {
+    std::move(it->second).Run(result);
+  }
+  start_lxd_container_callbacks_.erase(range.first, range.second);
+}
 void CrostiniManager::OnLaunchContainerApplication(
     LaunchContainerApplicationCallback callback,
     base::Optional<vm_tools::cicerone::LaunchContainerApplicationResponse>
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h
index 6bc25f7..1c0df50 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.h
+++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -44,6 +44,7 @@
   CONTAINER_DOWNLOAD_TIMED_OUT,
   CONTAINER_CREATE_CANCELLED,
   CONTAINER_CREATE_FAILED,
+  CONTAINER_START_CANCELLED,
   CONTAINER_START_FAILED,
   LAUNCH_CONTAINER_APPLICATION_FAILED,
   INSTALL_LINUX_PACKAGE_FAILED,
@@ -438,6 +439,8 @@
       const vm_tools::cicerone::LxdContainerDownloadingSignal& signal) override;
   void OnTremplinStarted(
       const vm_tools::cicerone::TremplinStartedSignal& signal) override;
+  void OnLxdContainerStarting(
+      const vm_tools::cicerone::LxdContainerStartingSignal& signal) override;
 
   void RemoveCrostini(std::string vm_name,
                       std::string container_name,
@@ -627,6 +630,12 @@
   std::multimap<std::pair<std::string, std::string>, CrostiniResultCallback>
       create_lxd_container_callbacks_;
 
+  // Pending StartLxdContainer callbacks are keyed by <vm_name, container_name>
+  // string pairs. These are used if StartLxdContainer indicates we need to
+  // wait for an LxdContainerStarting signal.
+  std::multimap<std::pair<std::string, std::string>, CrostiniResultCallback>
+      start_lxd_container_callbacks_;
+
   // Callbacks to run after Tremplin is started, keyed by vm_name. These are
   // used if StartTerminaVm completes but we need to wait from Tremplin to
   // start.
diff --git a/chrome/browser/chromeos/fileapi/external_file_url_loader_factory.cc b/chrome/browser/chromeos/fileapi/external_file_url_loader_factory.cc
index 67136f1..a4beac2 100644
--- a/chrome/browser/chromeos/fileapi/external_file_url_loader_factory.cc
+++ b/chrome/browser/chromeos/fileapi/external_file_url_loader_factory.cc
@@ -201,11 +201,9 @@
   }
 
   // network::mojom::URLLoader:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override {}
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override {}
   void ProceedWithResponse() override {}
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override {}
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_mode_detector.cc b/chrome/browser/chromeos/login/demo_mode/demo_mode_detector.cc
index 2e47825..4050f76 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_mode_detector.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_mode_detector.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/constants/chromeos_switches.h"
-#include "chromeos/dbus/dbus_switches.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_mode_detector_unittest.cc b/chrome/browser/chromeos/login/demo_mode/demo_mode_detector_unittest.cc
index 52b5a847..203f1906 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_mode_detector_unittest.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_mode_detector_unittest.cc
@@ -16,7 +16,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/constants/chromeos_switches.h"
-#include "chromeos/dbus/dbus_switches.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 #include "components/prefs/testing_pref_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
index 0295282..03d8c86 100644
--- a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
+++ b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
@@ -24,7 +24,7 @@
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/enrollment_status_chromeos.h"
 #include "chromeos/constants/chromeos_switches.h"
-#include "chromeos/dbus/dbus_switches.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_auth_policy_client.h"
 #include "chromeos/dbus/fake_update_engine_client.h"
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc b/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
index c307dcf..45e590c 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
@@ -47,9 +47,9 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_browser_process.h"
-#include "chromeos/constants/chromeos_paths.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_session_manager_client.h"
@@ -626,8 +626,8 @@
     UserImageManagerTest::SetUpOnMainThread();
 
     base::FilePath user_keys_dir;
-    ASSERT_TRUE(
-        base::PathService::Get(chromeos::DIR_USER_POLICY_KEYS, &user_keys_dir));
+    ASSERT_TRUE(base::PathService::Get(
+        chromeos::dbus_paths::DIR_USER_POLICY_KEYS, &user_keys_dir));
     const std::string sanitized_username =
         chromeos::CryptohomeClient::GetStubSanitizedUsername(cryptohome_id_);
     const base::FilePath user_key_file =
diff --git a/chrome/browser/chromeos/login/users/wallpaper_policy_browsertest.cc b/chrome/browser/chromeos/login/users/wallpaper_policy_browsertest.cc
index e81115a..9f6e097e 100644
--- a/chrome/browser/chromeos/login/users/wallpaper_policy_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper_policy_browsertest.cc
@@ -39,6 +39,7 @@
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_session_manager_client.h"
@@ -151,7 +152,8 @@
     std::unique_ptr<policy::UserPolicyBuilder> user_policy_builder(
         new policy::UserPolicyBuilder());
     base::FilePath user_keys_dir;
-    EXPECT_TRUE(base::PathService::Get(DIR_USER_POLICY_KEYS, &user_keys_dir));
+    EXPECT_TRUE(base::PathService::Get(dbus_paths::DIR_USER_POLICY_KEYS,
+                                       &user_keys_dir));
     const std::string sanitized_user_id =
         CryptohomeClient::GetStubSanitizedUsername(
             cryptohome::CreateAccountIdentifierFromAccountId(account_id));
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index 0b5fdc0..8291d26 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -68,7 +68,7 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/audio/cras_audio_handler.h"
 #include "chromeos/constants/chromeos_switches.h"
-#include "chromeos/dbus/dbus_switches.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
 #include "chromeos/dbus/fake_session_manager_client.h"
diff --git a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.cc b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.cc
index 7667b932..456e353 100644
--- a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.cc
+++ b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.cc
@@ -12,8 +12,8 @@
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chromeos/constants/chromeos_paths.h"
 #include "chromeos/constants/chromeos_switches.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/ownership/owner_key_util.h"
 #include "components/ownership/owner_key_util_impl.h"
@@ -75,8 +75,10 @@
   if (owner_key_util_.get())
     return owner_key_util_;
   base::FilePath public_key_path;
-  if (!base::PathService::Get(chromeos::FILE_OWNER_KEY, &public_key_path))
-    return NULL;
+  if (!base::PathService::Get(chromeos::dbus_paths::FILE_OWNER_KEY,
+                              &public_key_path)) {
+    return nullptr;
+  }
   owner_key_util_ = new ownership::OwnerKeyUtilImpl(public_key_path);
   return owner_key_util_;
 }
diff --git a/chrome/browser/chromeos/policy/affiliation_test_helper.cc b/chrome/browser/chromeos/policy/affiliation_test_helper.cc
index eb6d2938..c43d95f 100644
--- a/chrome/browser/chromeos/policy/affiliation_test_helper.cc
+++ b/chrome/browser/chromeos/policy/affiliation_test_helper.cc
@@ -20,9 +20,9 @@
 #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
-#include "chromeos/constants/chromeos_paths.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/fake_auth_policy_client.h"
 #include "chromeos/dbus/fake_session_manager_client.h"
@@ -51,8 +51,8 @@
   const AccountId account_id =
       AccountId::FromUserEmail(user_policy.policy_data().username());
   base::FilePath user_keys_dir;
-  ASSERT_TRUE(
-      base::PathService::Get(chromeos::DIR_USER_POLICY_KEYS, &user_keys_dir));
+  ASSERT_TRUE(base::PathService::Get(chromeos::dbus_paths::DIR_USER_POLICY_KEYS,
+                                     &user_keys_dir));
   const std::string sanitized_username =
       chromeos::CryptohomeClient::GetStubSanitizedUsername(
           cryptohome::CreateAccountIdentifierFromAccountId(account_id));
diff --git a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
index 0b0afec..3556a1e 100644
--- a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
+++ b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
 #include "chrome/common/chrome_paths.h"
 #include "chromeos/constants/chromeos_paths.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_session_manager_client.h"
 #include "chromeos/dbus/util/tpm_util.h"
@@ -34,8 +35,8 @@
 
 void WriteInstallAttributesFile(const std::string& install_attrs_blob) {
   base::FilePath install_attrs_file;
-  ASSERT_TRUE(base::PathService::Get(chromeos::FILE_INSTALL_ATTRIBUTES,
-                                     &install_attrs_file));
+  ASSERT_TRUE(base::PathService::Get(
+      chromeos::dbus_paths::FILE_INSTALL_ATTRIBUTES, &install_attrs_file));
   base::ScopedAllowBlockingForTesting allow_io;
   ASSERT_EQ(base::checked_cast<int>(install_attrs_blob.size()),
             base::WriteFile(install_attrs_file, install_attrs_blob.c_str(),
@@ -65,8 +66,8 @@
   OverridePaths();
 
   base::FilePath owner_key_file;
-  ASSERT_TRUE(
-      base::PathService::Get(chromeos::FILE_OWNER_KEY, &owner_key_file));
+  ASSERT_TRUE(base::PathService::Get(chromeos::dbus_paths::FILE_OWNER_KEY,
+                                     &owner_key_file));
   std::string owner_key_bits = device_policy()->GetPublicSigningKeyAsString();
   ASSERT_FALSE(owner_key_bits.empty());
   ASSERT_EQ(base::checked_cast<int>(owner_key_bits.length()),
diff --git a/chrome/browser/chromeos/policy/power_policy_browsertest.cc b/chrome/browser/chromeos/policy/power_policy_browsertest.cc
index 8fcc569..6a9ac319 100644
--- a/chrome/browser/chromeos/policy/power_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/power_policy_browsertest.cc
@@ -33,9 +33,9 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/constants/chromeos_paths.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_power_manager_client.h"
@@ -208,8 +208,8 @@
 
 void PowerPolicyBrowserTestBase::InstallUserKey() {
   base::FilePath user_keys_dir;
-  ASSERT_TRUE(
-      base::PathService::Get(chromeos::DIR_USER_POLICY_KEYS, &user_keys_dir));
+  ASSERT_TRUE(base::PathService::Get(chromeos::dbus_paths::DIR_USER_POLICY_KEYS,
+                                     &user_keys_dir));
   std::string sanitized_username =
       chromeos::CryptohomeClient::GetStubSanitizedUsername(
           cryptohome::CreateAccountIdentifierFromAccountId(
diff --git a/chrome/browser/chromeos/policy/pre_signin_policy_fetcher.cc b/chrome/browser/chromeos/policy/pre_signin_policy_fetcher.cc
index 6eb877a5..fdf3f1e5 100644
--- a/chrome/browser/chromeos/policy/pre_signin_policy_fetcher.cc
+++ b/chrome/browser/chromeos/policy/pre_signin_policy_fetcher.cc
@@ -16,10 +16,10 @@
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "base/time/time.h"
-#include "chromeos/constants/chromeos_paths.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/cryptohome/cryptohome_util.h"
 #include "chromeos/cryptohome/homedir_methods.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
@@ -112,7 +112,7 @@
   // are not signed).
   if (!policy_blob.empty() && !is_active_directory_managed_) {
     base::FilePath policy_key_dir;
-    CHECK(base::PathService::Get(chromeos::DIR_USER_POLICY_KEYS,
+    CHECK(base::PathService::Get(chromeos::dbus_paths::DIR_USER_POLICY_KEYS,
                                  &policy_key_dir));
     cached_policy_key_loader_ = std::make_unique<CachedPolicyKeyLoaderChromeOS>(
         cryptohome_client_, task_runner_, account_id_, policy_key_dir);
diff --git a/chrome/browser/chromeos/policy/pre_signin_policy_fetcher_unittest.cc b/chrome/browser/chromeos/policy/pre_signin_policy_fetcher_unittest.cc
index 0baa004..8a9cde4 100644
--- a/chrome/browser/chromeos/policy/pre_signin_policy_fetcher_unittest.cc
+++ b/chrome/browser/chromeos/policy/pre_signin_policy_fetcher_unittest.cc
@@ -16,8 +16,8 @@
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
-#include "chromeos/constants/chromeos_paths.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
@@ -63,7 +63,7 @@
     // are shared between session_manager and chrome through files) and set it
     // into PathService, so PreSigninPolicyFetcher will use it.
     ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
-    base::PathService::Override(chromeos::DIR_USER_POLICY_KEYS,
+    base::PathService::Override(chromeos::dbus_paths::DIR_USER_POLICY_KEYS,
                                 user_policy_keys_dir());
 
     auto cloud_policy_client = std::make_unique<MockCloudPolicyClient>();
diff --git a/chrome/browser/chromeos/policy/user_policy_manager_factory_chromeos.cc b/chrome/browser/chromeos/policy/user_policy_manager_factory_chromeos.cc
index 0361f76..f6bc98d 100644
--- a/chrome/browser/chromeos/policy/user_policy_manager_factory_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_policy_manager_factory_chromeos.cc
@@ -32,8 +32,8 @@
 #include "chrome/browser/policy/schema_registry_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/constants/chromeos_paths.h"
 #include "chromeos/constants/chromeos_switches.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/settings/install_attributes.h"
 #include "components/arc/arc_features.h"
@@ -360,8 +360,8 @@
   const base::FilePath external_data_dir =
       profile_dir.Append(kPolicy).Append(kPolicyExternalDataDir);
   base::FilePath policy_key_dir;
-  CHECK(
-      base::PathService::Get(chromeos::DIR_USER_POLICY_KEYS, &policy_key_dir));
+  CHECK(base::PathService::Get(chromeos::dbus_paths::DIR_USER_POLICY_KEYS,
+                               &policy_key_dir));
 
   std::unique_ptr<UserCloudPolicyStoreChromeOS> store =
       std::make_unique<UserCloudPolicyStoreChromeOS>(
diff --git a/chrome/browser/client_hints/client_hints.cc b/chrome/browser/client_hints/client_hints.cc
index 22d8bdf2..b65c5fc 100644
--- a/chrome/browser/client_hints/client_hints.cc
+++ b/chrome/browser/client_hints/client_hints.cc
@@ -215,9 +215,9 @@
 
 ClientHints::~ClientHints() = default;
 
-std::unique_ptr<net::HttpRequestHeaders>
-ClientHints::GetAdditionalNavigationRequestClientHintsHeaders(
-    const GURL& url) const {
+void ClientHints::GetAdditionalNavigationRequestClientHintsHeaders(
+    const GURL& url,
+    net::HttpRequestHeaders* additional_headers) const {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK_EQ(blink::kWebEffectiveConnectionTypeMappingCount,
             net::EFFECTIVE_CONNECTION_TYPE_4G + 1u);
@@ -226,26 +226,25 @@
 
   // Get the client hint headers.
   if (!url.is_valid())
-    return nullptr;
+    return;
 
   if (!url.SchemeIsHTTPOrHTTPS())
-    return nullptr;
+    return;
 
   if (url.SchemeIs(url::kHttpScheme) && !net::IsLocalhost(url))
-    return nullptr;
+    return;
 
   DCHECK(url.SchemeIs(url::kHttpsScheme) ||
          (url.SchemeIs(url::kHttpScheme) && net::IsLocalhost(url)));
 
   Profile* profile = Profile::FromBrowserContext(context_);
   if (!profile)
-    return nullptr;
+    return;
 
   // Check if |url| is allowed to run JavaScript. If not, client hints are not
   // attached to the requests that initiate on the browser side.
-  if (!IsJavaScriptAllowed(profile, url)) {
-    return nullptr;
-  }
+  if (!IsJavaScriptAllowed(profile, url))
+    return;
 
   ContentSettingsForOneType client_hints_host_settings;
   HostContentSettingsMapFactory::GetForProfile(profile)->GetSettingsForOneType(
@@ -257,9 +256,6 @@
   GetAllowedClientHintsFromSource(
       url /* resource url */, client_hints_host_settings, &web_client_hints);
 
-  std::unique_ptr<net::HttpRequestHeaders> additional_headers(
-      std::make_unique<net::HttpRequestHeaders>());
-
   // Currently, only "device-memory" client hint request header is added from
   // the browser process.
   if (web_client_hints.IsEnabled(
@@ -384,7 +380,6 @@
   // headers stay attached to the redirected request. Consider removing/adding
   // the client hints headers if the request is redirected with a change in
   // scheme or a change in the origin.
-  return additional_headers;
 }
 
 }  // namespace client_hints
diff --git a/chrome/browser/client_hints/client_hints.h b/chrome/browser/client_hints/client_hints.h
index 4cc275b2..e3906b79 100644
--- a/chrome/browser/client_hints/client_hints.h
+++ b/chrome/browser/client_hints/client_hints.h
@@ -43,10 +43,11 @@
   explicit ClientHints(content::BrowserContext* context);
   ~ClientHints() override;
 
-  // Allow the embedder to return additional headers related to client hints
-  // that should be sent when fetching |url|. May return a nullptr.
-  std::unique_ptr<net::HttpRequestHeaders>
-  GetAdditionalNavigationRequestClientHintsHeaders(const GURL& url) const;
+  // Allow the embedder to add headers related to client hints
+  // that should be sent when fetching |url|.
+  void GetAdditionalNavigationRequestClientHintsHeaders(
+      const GURL& url,
+      net::HttpRequestHeaders* additional_headers) const;
 
  private:
   content::BrowserContext* context_;
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_unittest.cc b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_unittest.cc
index 5dea19b..8ed3e7d9 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_unittest.cc
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_unittest.cc
@@ -19,7 +19,7 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/proxy_config/proxy_config_pref_names.h"
-#include "content/public/browser/navigation_handle.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/test/test_network_connection_tracker.h"
 #include "services/network/test/test_network_quality_tracker.h"
@@ -382,16 +382,14 @@
 }
 
 TEST_F(DataReductionProxyChromeSettingsTest, CreateDataBasic) {
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(GURL(kUrl),
-                                                                  main_rfh());
-  std::string headers = "HTTP/1.0 200 OK\n";
-  handle->CallWillProcessResponseForTesting(
-      main_rfh(),
-      net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()), false,
-      net::ProxyServer::Direct());
+  content::MockNavigationHandle handle(GURL(kUrl), main_rfh());
+  std::string raw_headers = "HTTP/1.0 200 OK\n";
+  scoped_refptr<net::HttpResponseHeaders> headers =
+      new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+          raw_headers.c_str(), raw_headers.size()));
+  handle.set_response_headers(headers.get());
   auto data = drp_chrome_settings_->CreateDataFromNavigationHandle(
-      handle.get(), handle->GetResponseHeaders());
+      &handle, headers.get());
 
   EXPECT_EQ(data->request_url(), GURL(kUrl));
   EXPECT_EQ(data->effective_connection_type(),
@@ -402,63 +400,60 @@
 }
 
 TEST_F(DataReductionProxyChromeSettingsTest, CreateDataUsedDataReductionProxy) {
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(GURL(kUrl),
-                                                                  main_rfh());
-  std::string headers = "HTTP/1.0 200 OK\n";
-  handle->CallWillProcessResponseForTesting(
-      main_rfh(),
-      net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()), false,
-      net::ProxyServer::FromPacString(kProxyPac));
+  content::MockNavigationHandle handle(GURL(kUrl), main_rfh());
+  handle.set_proxy_server(net::ProxyServer::FromPacString(kProxyPac));
+  std::string raw_headers = "HTTP/1.0 200 OK\n";
+  scoped_refptr<net::HttpResponseHeaders> headers =
+      new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+          raw_headers.c_str(), raw_headers.size()));
+  handle.set_response_headers(headers.get());
   auto data = drp_chrome_settings_->CreateDataFromNavigationHandle(
-      handle.get(), handle->GetResponseHeaders());
+      &handle, headers.get());
 
   EXPECT_TRUE(data->used_data_reduction_proxy());
 }
 
 TEST_F(DataReductionProxyChromeSettingsTest, CreateDataCachedResponse) {
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(GURL(kUrl),
-                                                                  main_rfh());
-  std::string headers = "HTTP/1.0 200 OK\nchrome-proxy: foo\n";
-  handle->CallWillProcessResponseForTesting(
-      main_rfh(),
-      net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()), true,
-      net::ProxyServer::Direct());
+  std::string raw_headers =
+      "HTTP/1.0 200 OK\n"
+      "chrome-proxy: foo\n";
+  content::MockNavigationHandle handle(GURL(kUrl), main_rfh());
+  scoped_refptr<net::HttpResponseHeaders> headers =
+      new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+          raw_headers.c_str(), raw_headers.size()));
+  handle.set_response_headers(headers.get());
+  handle.set_was_response_cached(true);
   auto data = drp_chrome_settings_->CreateDataFromNavigationHandle(
-      handle.get(), handle->GetResponseHeaders());
+      &handle, headers.get());
 
   EXPECT_TRUE(data->was_cached_data_reduction_proxy_response());
 }
 
 TEST_F(DataReductionProxyChromeSettingsTest, CreateHTTPSDataCachedResponse) {
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL("https://secure.com"), main_rfh());
-  std::string headers = "HTTP/1.0 200 OK\nchrome-proxy: foo\n";
-  handle->CallWillProcessResponseForTesting(
-      main_rfh(),
-      net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()), true,
-      net::ProxyServer::Direct());
+  std::string raw_headers = "HTTP/1.0 200 OK\nchrome-proxy: foo\n";
+  content::MockNavigationHandle handle(GURL("https://secure.com"), main_rfh());
+  scoped_refptr<net::HttpResponseHeaders> headers =
+      new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+          raw_headers.c_str(), raw_headers.size()));
+  handle.set_response_headers(headers.get());
+  handle.set_was_response_cached(true);
   auto data = drp_chrome_settings_->CreateDataFromNavigationHandle(
-      handle.get(), handle->GetResponseHeaders());
+      &handle, headers.get());
 
   EXPECT_FALSE(data->was_cached_data_reduction_proxy_response());
 }
 
 TEST_F(DataReductionProxyChromeSettingsTest, CreateDataWithLitePage) {
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(GURL(kUrl),
-                                                                  main_rfh());
-  std::string headers =
+  std::string raw_headers =
       "HTTP/1.0 200 OK\n"
       "chrome-proxy-content-transform: lite-page\n";
-  handle->CallWillProcessResponseForTesting(
-      main_rfh(),
-      net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()), false,
-      net::ProxyServer::Direct());
+  content::MockNavigationHandle handle(GURL(kUrl), main_rfh());
+  scoped_refptr<net::HttpResponseHeaders> headers =
+      new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+          raw_headers.c_str(), raw_headers.size()));
+  handle.set_response_headers(headers.get());
   auto data = drp_chrome_settings_->CreateDataFromNavigationHandle(
-      handle.get(), handle->GetResponseHeaders());
+      &handle, headers.get());
 
   EXPECT_TRUE(data->lite_page_received());
   EXPECT_FALSE(data->lofi_received());
@@ -466,18 +461,16 @@
 }
 
 TEST_F(DataReductionProxyChromeSettingsTest, CreateDataWithLofiPolicyReceived) {
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(GURL(kUrl),
-                                                                  main_rfh());
-  std::string headers =
+  std::string raw_headers =
       "HTTP/1.0 200 OK\n"
       "chrome-proxy: page-policies=empty-image\n";
-  handle->CallWillProcessResponseForTesting(
-      main_rfh(),
-      net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()), false,
-      net::ProxyServer::Direct());
+  content::MockNavigationHandle handle(GURL(kUrl), main_rfh());
+  scoped_refptr<net::HttpResponseHeaders> headers =
+      new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+          raw_headers.c_str(), raw_headers.size()));
+  handle.set_response_headers(headers.get());
   auto data = drp_chrome_settings_->CreateDataFromNavigationHandle(
-      handle.get(), handle->GetResponseHeaders());
+      &handle, headers.get());
 
   EXPECT_FALSE(data->lite_page_received());
   EXPECT_FALSE(data->lofi_received());
@@ -485,18 +478,16 @@
 }
 
 TEST_F(DataReductionProxyChromeSettingsTest, CreateDataWithLofiReceived) {
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(GURL(kUrl),
-                                                                  main_rfh());
-  std::string headers =
+  std::string raw_headers =
       "HTTP/1.0 200 OK\n"
       "chrome-proxy-content-transform: empty-image\n";
-  handle->CallWillProcessResponseForTesting(
-      main_rfh(),
-      net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()), false,
-      net::ProxyServer::Direct());
+  content::MockNavigationHandle handle(GURL(kUrl), main_rfh());
+  scoped_refptr<net::HttpResponseHeaders> headers =
+      new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+          raw_headers.c_str(), raw_headers.size()));
+  handle.set_response_headers(headers.get());
   auto data = drp_chrome_settings_->CreateDataFromNavigationHandle(
-      handle.get(), handle->GetResponseHeaders());
+      &handle, headers.get());
 
   EXPECT_FALSE(data->lite_page_received());
   EXPECT_TRUE(data->lofi_received());
diff --git a/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry_unittest.cc b/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry_unittest.cc
index 2f3ccaa..945c5a1 100644
--- a/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry_unittest.cc
@@ -11,9 +11,9 @@
 #include "chrome/browser/extensions/api/declarative_content/content_predicate_evaluator.h"
 #include "chrome/browser/extensions/test_extension_environment.h"
 #include "chrome/test/base/testing_profile.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/frame_navigate_params.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/test_renderer_host.h"
 #include "extensions/common/extension.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -153,11 +153,10 @@
 
   std::unique_ptr<content::WebContents> tab = env()->MakeTab();
   registry->MonitorWebContentsForRuleEvaluation(tab.get());
-  std::unique_ptr<content::NavigationHandle> navigation_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(), tab->GetMainFrame(), true);
+  content::MockNavigationHandle navigation_handle;
+  navigation_handle.set_has_committed(true);
 
-  registry->DidFinishNavigation(tab.get(), navigation_handle.get());
+  registry->DidFinishNavigation(tab.get(), &navigation_handle);
   EXPECT_EQ(0u, registry->GetActiveRulesCountForTesting());
 
   // Add a rule.
@@ -183,27 +182,25 @@
       "{\"page_action\": {}}"));
   registry->AddRulesImpl(extension->id(), rules);
 
-  registry->DidFinishNavigation(tab.get(), navigation_handle.get());
+  registry->DidFinishNavigation(tab.get(), &navigation_handle);
   EXPECT_EQ(0u, registry->GetActiveRulesCountForTesting());
 
   evaluator->RequestImmediateEvaluation(tab.get(), true);
   EXPECT_EQ(1u, registry->GetActiveRulesCountForTesting());
 
   // Closing the tab should erase its entry from active_rules_.
-  navigation_handle.reset();
   tab.reset();
   EXPECT_EQ(0u, registry->GetActiveRulesCountForTesting());
 
   tab = env()->MakeTab();
-  navigation_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(), tab->GetMainFrame(), true);
+  content::MockNavigationHandle navigation_handle2;
+  navigation_handle2.set_has_committed(true);
   registry->MonitorWebContentsForRuleEvaluation(tab.get());
   evaluator->RequestImmediateEvaluation(tab.get(), true);
   EXPECT_EQ(1u, registry->GetActiveRulesCountForTesting());
 
   evaluator->RequestEvaluationOnNextOperation(tab.get(), false);
-  registry->DidFinishNavigation(tab.get(), navigation_handle.get());
+  registry->DidFinishNavigation(tab.get(), &navigation_handle2);
   EXPECT_EQ(0u, registry->GetActiveRulesCountForTesting());
 }
 
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc
index 3f6ee17..ae8d03c9 100644
--- a/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/extensions/api/declarative_content/declarative_content_condition_tracker_test.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "extensions/common/extension_messages.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -301,10 +302,10 @@
 
   // Check that an in-page navigation has no effect on the matching selectors.
   {
-    std::unique_ptr<content::NavigationHandle> navigation_handle =
-        content::NavigationHandle::CreateNavigationHandleForTesting(
-            GURL(), tab->GetMainFrame(), true, net::OK, true);
-    tracker_.OnWebContentsNavigation(tab.get(), navigation_handle.get());
+    content::MockNavigationHandle test_handle;
+    test_handle.set_has_committed(true);
+    test_handle.set_is_same_document(true);
+    tracker_.OnWebContentsNavigation(tab.get(), &test_handle);
     EXPECT_TRUE(tracker_.EvaluatePredicate(predicate.get(), tab.get()));
     EXPECT_EQ(expected_evaluation_requests, delegate_.evaluation_requests());
   }
@@ -312,10 +313,9 @@
   // Check that a non in-page navigation clears the matching selectors and
   // requests condition evaluation.
   {
-    std::unique_ptr<content::NavigationHandle> navigation_handle =
-        content::NavigationHandle::CreateNavigationHandleForTesting(
-            GURL(), tab->GetMainFrame(), true);
-    tracker_.OnWebContentsNavigation(tab.get(), navigation_handle.get());
+    content::MockNavigationHandle test_handle;
+    test_handle.set_has_committed(true);
+    tracker_.OnWebContentsNavigation(tab.get(), &test_handle);
     EXPECT_FALSE(tracker_.EvaluatePredicate(predicate.get(), tab.get()));
     EXPECT_EQ(++expected_evaluation_requests, delegate_.evaluation_requests());
   }
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker_unittest.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker_unittest.cc
index b27be381..3b74e76 100644
--- a/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_content/declarative_content_is_bookmarked_condition_tracker_unittest.cc
@@ -22,7 +22,6 @@
 #include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
 #include "components/bookmarks/test/bookmark_test_helpers.h"
 #include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_builder.h"
@@ -238,10 +237,7 @@
   // Navigate the first tab to a URL that we will bookmark.
   delegate_.evaluation_requests().clear();
   LoadURL(tabs[0].get(), GURL("http://bookmarked/"));
-  std::unique_ptr<content::NavigationHandle> navigation_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(), tabs[0]->GetMainFrame(), true);
-  tracker_->OnWebContentsNavigation(tabs[0].get(), navigation_handle.get());
+  tracker_->OnWebContentsNavigation(tabs[0].get(), nullptr);
   EXPECT_THAT(delegate_.evaluation_requests(),
               UnorderedElementsAre(tabs[0].get()));
   EXPECT_TRUE(CheckPredicates(tabs[0].get(), false));
@@ -284,10 +280,7 @@
   // Navigate the first tab to a URL that we will bookmark.
   delegate_.evaluation_requests().clear();
   LoadURL(tabs[0].get(), GURL("http://bookmarked/"));
-  std::unique_ptr<content::NavigationHandle> navigation_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(), tabs[0]->GetMainFrame(), true);
-  tracker_->OnWebContentsNavigation(tabs[0].get(), navigation_handle.get());
+  tracker_->OnWebContentsNavigation(tabs[0].get(), nullptr);
   EXPECT_THAT(delegate_.evaluation_requests(),
               UnorderedElementsAre(tabs[0].get()));
   EXPECT_TRUE(CheckPredicates(tabs[0].get(), false));
@@ -388,10 +381,7 @@
   // Navigate the first tab to one bookmarked URL.
   delegate_.evaluation_requests().clear();
   LoadURL(tabs[0].get(), GURL("http://bookmarked1/"));
-  std::unique_ptr<content::NavigationHandle> navigation_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(), tabs[0]->GetMainFrame(), true);
-  tracker_->OnWebContentsNavigation(tabs[0].get(), navigation_handle.get());
+  tracker_->OnWebContentsNavigation(tabs[0].get(), nullptr);
   EXPECT_THAT(delegate_.evaluation_requests(),
               UnorderedElementsAre(tabs[0].get()));
   EXPECT_TRUE(CheckPredicates(tabs[0].get(), true));
@@ -402,7 +392,7 @@
   // bookmarked state hasn't.
   delegate_.evaluation_requests().clear();
   LoadURL(tabs[0].get(), GURL("http://bookmarked2/"));
-  tracker_->OnWebContentsNavigation(tabs[0].get(), navigation_handle.get());
+  tracker_->OnWebContentsNavigation(tabs[0].get(), nullptr);
   EXPECT_THAT(delegate_.evaluation_requests(),
               UnorderedElementsAre(tabs[0].get()));
   EXPECT_TRUE(CheckPredicates(tabs[0].get(), true));
@@ -411,7 +401,7 @@
   // Navigate the first tab to a non-bookmarked URL.
   delegate_.evaluation_requests().clear();
   LoadURL(tabs[0].get(), GURL("http://not-bookmarked1/"));
-  tracker_->OnWebContentsNavigation(tabs[0].get(), navigation_handle.get());
+  tracker_->OnWebContentsNavigation(tabs[0].get(), nullptr);
   EXPECT_THAT(delegate_.evaluation_requests(),
               UnorderedElementsAre(tabs[0].get()));
   EXPECT_TRUE(CheckPredicates(tabs[0].get(), false));
@@ -422,7 +412,7 @@
   // bookmarked state hasn't.
   delegate_.evaluation_requests().clear();
   LoadURL(tabs[0].get(), GURL("http://not-bookmarked2/"));
-  tracker_->OnWebContentsNavigation(tabs[0].get(), navigation_handle.get());
+  tracker_->OnWebContentsNavigation(tabs[0].get(), nullptr);
   EXPECT_THAT(delegate_.evaluation_requests(),
               UnorderedElementsAre(tabs[0].get()));
   EXPECT_TRUE(CheckPredicates(tabs[0].get(), false));
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_page_url_condition_tracker_unittest.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_page_url_condition_tracker_unittest.cc
index 88bcc92..cea7cf1 100644
--- a/chrome/browser/extensions/api/declarative_content/declarative_content_page_url_condition_tracker_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_content/declarative_content_page_url_condition_tracker_unittest.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/extensions/api/declarative_content/declarative_content_condition_tracker_test.h"
 #include "components/url_matcher/url_matcher.h"
 #include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -252,10 +251,7 @@
   // evaluation request.
   LoadURL(tab.get(), GURL("http://test1/"));
   delegate_.evaluation_requests().clear();
-  std::unique_ptr<content::NavigationHandle> navigation_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(), tab->GetMainFrame(), true);
-  tracker_.OnWebContentsNavigation(tab.get(), navigation_handle.get());
+  tracker_.OnWebContentsNavigation(tab.get(), nullptr);
   EXPECT_THAT(delegate_.evaluation_requests(),
               UnorderedElementsAre(tab.get()));
 
@@ -263,7 +259,7 @@
   // URL results in an evaluation request.
   LoadURL(tab.get(), GURL("http://test1/a"));
   delegate_.evaluation_requests().clear();
-  tracker_.OnWebContentsNavigation(tab.get(), navigation_handle.get());
+  tracker_.OnWebContentsNavigation(tab.get(), nullptr);
   EXPECT_THAT(delegate_.evaluation_requests(),
               UnorderedElementsAre(tab.get()));
 
@@ -271,7 +267,7 @@
   // URL results in an evaluation request.
   delegate_.evaluation_requests().clear();
   LoadURL(tab.get(), GURL("http://test2/"));
-  tracker_.OnWebContentsNavigation(tab.get(), navigation_handle.get());
+  tracker_.OnWebContentsNavigation(tab.get(), nullptr);
   EXPECT_THAT(delegate_.evaluation_requests(),
               UnorderedElementsAre(tab.get()));
 
@@ -279,7 +275,7 @@
   // non-matching URL results in an evaluation request.
   delegate_.evaluation_requests().clear();
   LoadURL(tab.get(), GURL("http://test2/a"));
-  tracker_.OnWebContentsNavigation(tab.get(), navigation_handle.get());
+  tracker_.OnWebContentsNavigation(tab.get(), nullptr);
   EXPECT_THAT(delegate_.evaluation_requests(),
               UnorderedElementsAre(tab.get()));
 
diff --git a/chrome/browser/extensions/chrome_url_request_util.cc b/chrome/browser/extensions/chrome_url_request_util.cc
index 765789c..f1abbab 100644
--- a/chrome/browser/extensions/chrome_url_request_util.cc
+++ b/chrome/browser/extensions/chrome_url_request_util.cc
@@ -149,11 +149,9 @@
   }
 
   // mojom::URLLoader implementation:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override {
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override {
     NOTREACHED() << "No redirects for local file loads.";
   }
   // Current implementation reads all resource data at start of resource
diff --git a/chrome/browser/extensions/extension_navigation_throttle_unittest.cc b/chrome/browser/extensions/extension_navigation_throttle_unittest.cc
index 341f369..86aa59f 100644
--- a/chrome/browser/extensions/extension_navigation_throttle_unittest.cc
+++ b/chrome/browser/extensions/extension_navigation_throttle_unittest.cc
@@ -11,6 +11,7 @@
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/common/content_client.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/web_contents_tester.h"
@@ -72,19 +73,18 @@
       content::RenderFrameHost* host,
       const GURL& extension_url,
       NavigationThrottle::ThrottleAction expected_will_start_result) {
+    content::MockNavigationHandle test_handle(extension_url, host);
+    test_handle.set_starting_site_instance(host->GetSiteInstance());
+    auto throttle = std::make_unique<ExtensionNavigationThrottle>(&test_handle);
+
     // First subtest: direct navigation to |extension_url|.
-    std::unique_ptr<content::NavigationHandle> handle =
-        content::NavigationHandle::CreateNavigationHandleForTesting(
-            extension_url, host);
-    EXPECT_EQ(expected_will_start_result,
-              handle->CallWillStartRequestForTesting())
+    EXPECT_EQ(expected_will_start_result, throttle->WillStartRequest().action())
         << extension_url;
 
-    // Reset the handle for a second subtest: server redirect to
+    // Second subtest: server redirect to
     // |extension_url|.
     GURL http_url("https://example.com");
-    handle = content::NavigationHandle::CreateNavigationHandleForTesting(
-        http_url, host);
+    test_handle.set_url(http_url);
 
     // TODO(nick): https://crbug.com/695421 Once PlzNavigate is enabled 100%, it
     // should be possible to support return values other than PROCEED and CANCEL
@@ -94,13 +94,11 @@
             ? NavigationThrottle::PROCEED
             : NavigationThrottle::CANCEL;
     EXPECT_EQ(NavigationThrottle::PROCEED,
-              handle->CallWillStartRequestForTesting())
+              throttle->WillStartRequest().action())
         << http_url;
+    test_handle.set_url(extension_url);
     EXPECT_EQ(expected_will_redirect_result,
-              handle->CallWillRedirectRequestForTesting(
-                  extension_url,
-                  /*new_method_is_post=*/false, http_url,
-                  /*new_is_external_protocol=*/false))
+              throttle->WillRedirectRequest().action())
         << extension_url;
   }
 
diff --git a/chrome/browser/extensions/user_script_listener_unittest.cc b/chrome/browser/extensions/user_script_listener_unittest.cc
index 78ed94d..f956673 100644
--- a/chrome/browser/extensions/user_script_listener_unittest.cc
+++ b/chrome/browser/extensions/user_script_listener_unittest.cc
@@ -25,6 +25,7 @@
 #include "content/public/browser/navigation_throttle.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/test_utils.h"
@@ -98,19 +99,9 @@
         profile_, std::move(instance));
   }
 
+  void MarkNavigationResumed() { was_navigation_resumed_ = true; }
+
  protected:
-  NavigationThrottle::ThrottleCheckResult StartTestRequest(
-      const std::string& url_string) {
-    handle_ = content::NavigationHandle::CreateNavigationHandleForTesting(
-        GURL(url_string), web_contents_->GetMainFrame());
-
-    std::unique_ptr<NavigationThrottle> throttle =
-        listener_.CreateNavigationThrottle(handle_.get());
-    if (throttle)
-      handle_->RegisterThrottleForTesting(std::move(throttle));
-    return handle_->CallWillStartRequestForTesting();
-  }
-
   void LoadTestExtension() {
     base::FilePath test_dir;
     ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
@@ -132,14 +123,24 @@
                               UnloadedExtensionReason::DISABLE);
   }
 
+  std::unique_ptr<NavigationThrottle> CreateListenerNavigationThrottle(
+      content::NavigationHandle* handle) {
+    std::unique_ptr<NavigationThrottle> throttle =
+        listener_.CreateNavigationThrottle(handle);
+    throttle->set_resume_callback_for_testing(
+        base::BindRepeating(&UserScriptListenerTest::MarkNavigationResumed,
+                            base::Unretained(this)));
+    return throttle;
+  }
+
   content::TestBrowserThreadBundle thread_bundle_;
   content::RenderViewHostTestEnabler rvh_test_enabler_;
   std::unique_ptr<TestingProfileManager> profile_manager_;
   UserScriptListener listener_;
   TestingProfile* profile_ = nullptr;
   ExtensionService* service_ = nullptr;
+  bool was_navigation_resumed_ = false;
   std::unique_ptr<content::WebContents> web_contents_;
-  std::unique_ptr<content::NavigationHandle> handle_;
 #if defined(OS_CHROMEOS)
   std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
 #endif
@@ -150,46 +151,60 @@
 TEST_F(UserScriptListenerTest, DelayAndUpdate) {
   LoadTestExtension();
 
-  EXPECT_EQ(NavigationThrottle::DEFER, StartTestRequest(kMatchingUrl));
+  content::MockNavigationHandle handle(GURL(kMatchingUrl),
+                                       web_contents_->GetMainFrame());
+  std::unique_ptr<NavigationThrottle> throttle =
+      CreateListenerNavigationThrottle(&handle);
+  EXPECT_EQ(NavigationThrottle::DEFER, throttle->WillStartRequest());
 
   content::NotificationService::current()->Notify(
       extensions::NOTIFICATION_USER_SCRIPTS_UPDATED,
       content::Source<Profile>(profile_),
       content::NotificationService::NoDetails());
   base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(handle_->IsDeferredForTesting());
+  EXPECT_TRUE(was_navigation_resumed_);
 }
 
 TEST_F(UserScriptListenerTest, DelayAndUnload) {
   LoadTestExtension();
 
-  EXPECT_EQ(NavigationThrottle::DEFER, StartTestRequest(kMatchingUrl));
+  content::MockNavigationHandle handle(GURL(kMatchingUrl),
+                                       web_contents_->GetMainFrame());
+  std::unique_ptr<NavigationThrottle> throttle =
+      CreateListenerNavigationThrottle(&handle);
+  EXPECT_EQ(NavigationThrottle::DEFER, throttle->WillStartRequest());
 
   UnloadTestExtension();
   base::RunLoop().RunUntilIdle();
 
   // This is still not enough to start delayed requests. We have to notify the
   // listener that the user scripts have been updated.
-  EXPECT_TRUE(handle_->IsDeferredForTesting());
+  EXPECT_FALSE(was_navigation_resumed_);
 
   content::NotificationService::current()->Notify(
       extensions::NOTIFICATION_USER_SCRIPTS_UPDATED,
       content::Source<Profile>(profile_),
       content::NotificationService::NoDetails());
   base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(handle_->IsDeferredForTesting());
+  EXPECT_TRUE(was_navigation_resumed_);
 }
 
 TEST_F(UserScriptListenerTest, NoDelayNoExtension) {
-  EXPECT_EQ(NavigationThrottle::PROCEED, StartTestRequest(kMatchingUrl));
-  EXPECT_FALSE(handle_->IsDeferredForTesting());
+  content::MockNavigationHandle handle(GURL(kMatchingUrl),
+                                       web_contents_->GetMainFrame());
+  std::unique_ptr<NavigationThrottle> throttle =
+      listener_.CreateNavigationThrottle(&handle);
+  EXPECT_EQ(nullptr, throttle);
 }
 
 TEST_F(UserScriptListenerTest, NoDelayNotMatching) {
   LoadTestExtension();
 
-  EXPECT_EQ(NavigationThrottle::PROCEED, StartTestRequest(kNotMatchingUrl));
-  EXPECT_FALSE(handle_->IsDeferredForTesting());
+  content::MockNavigationHandle handle(GURL(kNotMatchingUrl),
+                                       web_contents_->GetMainFrame());
+  std::unique_ptr<NavigationThrottle> throttle =
+      listener_.CreateNavigationThrottle(&handle);
+  EXPECT_EQ(nullptr, throttle);
 }
 
 TEST_F(UserScriptListenerTest, MultiProfile) {
@@ -209,7 +224,11 @@
   registry->AddEnabled(extension);
   registry->TriggerOnLoaded(extension.get());
 
-  EXPECT_EQ(NavigationThrottle::DEFER, StartTestRequest(kMatchingUrl));
+  content::MockNavigationHandle handle(GURL(kMatchingUrl),
+                                       web_contents_->GetMainFrame());
+  std::unique_ptr<NavigationThrottle> throttle =
+      CreateListenerNavigationThrottle(&handle);
+  EXPECT_EQ(NavigationThrottle::DEFER, throttle->WillStartRequest());
 
   // When the first profile's user scripts are ready, the request should still
   // be blocked waiting for profile2.
@@ -218,7 +237,7 @@
       content::Source<Profile>(profile_),
       content::NotificationService::NoDetails());
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(handle_->IsDeferredForTesting());
+  EXPECT_FALSE(was_navigation_resumed_);
 
   // After profile2 is ready, the request should proceed.
   content::NotificationService::current()->Notify(
@@ -226,7 +245,7 @@
       content::Source<Profile>(profile2),
       content::NotificationService::NoDetails());
   base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(handle_->IsDeferredForTesting());
+  EXPECT_TRUE(was_navigation_resumed_);
 }
 
 // Test when the script updated notification occurs before the throttle's
@@ -234,11 +253,10 @@
 // throttles.
 TEST_F(UserScriptListenerTest, ResumeBeforeStart) {
   LoadTestExtension();
-  handle_ = content::NavigationHandle::CreateNavigationHandleForTesting(
-      GURL(kMatchingUrl), web_contents_->GetMainFrame());
-
+  content::MockNavigationHandle handle(GURL(kMatchingUrl),
+                                       web_contents_->GetMainFrame());
   std::unique_ptr<NavigationThrottle> throttle =
-      listener_.CreateNavigationThrottle(handle_.get());
+      listener_.CreateNavigationThrottle(&handle);
   ASSERT_TRUE(throttle);
 
   content::NotificationService::current()->Notify(
diff --git a/chrome/browser/media/media_engagement_contents_observer_unittest.cc b/chrome/browser/media/media_engagement_contents_observer_unittest.cc
index d3dd8c9..5796ae2 100644
--- a/chrome/browser/media/media_engagement_contents_observer_unittest.cc
+++ b/chrome/browser/media/media_engagement_contents_observer_unittest.cc
@@ -24,8 +24,8 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/ukm/test_ukm_recorder.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/test_service_manager_context.h"
 #include "content/public/test/web_contents_tester.h"
 #include "media/base/media_switches.h"
@@ -269,10 +269,11 @@
   }
 
   void Navigate(GURL url) {
-    std::unique_ptr<content::NavigationHandle> test_handle =
-        content::NavigationHandle::CreateNavigationHandleForTesting(
-            GURL(url), main_rfh(), true /** committed */);
-    contents_observer_->DidFinishNavigation(test_handle.get());
+    content::MockNavigationHandle test_handle(GURL(url), main_rfh());
+    contents_observer_->ReadyToCommitNavigation(&test_handle);
+
+    test_handle.set_has_committed(true);
+    contents_observer_->DidFinishNavigation(&test_handle);
   }
 
   scoped_refptr<MediaEngagementSession> GetOrCreateSession(
diff --git a/chrome/browser/net/dns_probe_browsertest.cc b/chrome/browser/net/dns_probe_browsertest.cc
index 3b0a5f20..a65c1e8a 100644
--- a/chrome/browser/net/dns_probe_browsertest.cc
+++ b/chrome/browser/net/dns_probe_browsertest.cc
@@ -165,11 +165,9 @@
   void OnConnectionError() { delete this; }
 
   // mojom::URLLoader implementation:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override {}
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override {}
   void ProceedWithResponse() override {}
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override {}
diff --git a/chrome/browser/net/net_error_tab_helper_unittest.cc b/chrome/browser/net/net_error_tab_helper_unittest.cc
index dcb1416..f3258b61 100644
--- a/chrome/browser/net/net_error_tab_helper_unittest.cc
+++ b/chrome/browser/net/net_error_tab_helper_unittest.cc
@@ -8,7 +8,7 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/error_page/common/net_error_info.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/navigation_handle.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_renderer_host.h"
 #include "net/base/net_errors.h"
@@ -144,13 +144,12 @@
       net_error = net::ERR_NAME_NOT_RESOLVED;
     else
       net_error = net::ERR_TIMED_OUT;
-    std::unique_ptr<content::NavigationHandle> navigation_handle(
-        content::NavigationHandle::CreateNavigationHandleForTesting(
-            bogus_url_,
-            (main_frame == MAIN_FRAME) ? main_rfh() : subframe_,
-            true,
-            net_error));
-    // The destructor will call tab_helper_->DidFinishNavigation.
+    content::MockNavigationHandle navigation_handle(
+        bogus_url_, (main_frame == MAIN_FRAME) ? main_rfh() : subframe_);
+    navigation_handle.set_net_error_code(net_error);
+    navigation_handle.set_has_committed(true);
+    navigation_handle.set_is_error_page(true);
+    tab_helper_->DidFinishNavigation(&navigation_handle);
   }
 
   void FinishProbe(DnsProbeStatus status) { tab_helper_->FinishProbe(status); }
diff --git a/chrome/browser/offline_pages/background_loader_offliner_unittest.cc b/chrome/browser/offline_pages/background_loader_offliner_unittest.cc
index 01d31d6..cbe029ff 100644
--- a/chrome/browser/offline_pages/background_loader_offliner_unittest.cc
+++ b/chrome/browser/offline_pages/background_loader_offliner_unittest.cc
@@ -27,8 +27,8 @@
 #include "components/prefs/pref_service.h"
 #include "components/previews/content/previews_user_data.h"
 #include "content/public/browser/mhtml_extra_parts.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/web_contents_tester.h"
@@ -596,12 +596,13 @@
                                       progress_callback()));
   // Create handle with net error code.
   // Called after calling LoadAndSave so we have web_contents to work with.
-  std::unique_ptr<content::NavigationHandle> handle(
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          kHttpUrl, offliner()->web_contents()->GetMainFrame(), true,
-          net::Error::ERR_NAME_NOT_RESOLVED));
-  // NavigationHandle destruction will trigger DidFinishNavigation code.
-  handle.reset();
+  content::MockNavigationHandle handle(
+      kHttpUrl, offliner()->web_contents()->GetMainFrame());
+  handle.set_has_committed(true);
+  handle.set_is_error_page(true);
+  handle.set_net_error_code(net::Error::ERR_NAME_NOT_RESOLVED);
+  offliner()->DidFinishNavigation(&handle);
+
   histograms().ExpectBucketCount(
       "OfflinePages.Background.LoadingErrorStatusCode.async_loading",
       -105,  // ERR_NAME_NOT_RESOLVED
@@ -623,14 +624,13 @@
 
   // Create handle with net error code.
   // Called after calling LoadAndSave so we have web_contents to work with.
-  std::unique_ptr<content::NavigationHandle> handle(
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          kHttpUrl, offliner()->web_contents()->GetMainFrame(), true,
-          net::Error::ERR_INTERNET_DISCONNECTED));
-  // Call DidFinishNavigation with handle that contains error.
-  offliner()->DidFinishNavigation(handle.get());
-  // NavigationHandle is always destroyed after finishing navigation.
-  handle.reset();
+  content::MockNavigationHandle handle(
+      kHttpUrl, offliner()->web_contents()->GetMainFrame());
+  handle.set_has_committed(true);
+  handle.set_is_error_page(true);
+  handle.set_net_error_code(net::Error::ERR_INTERNET_DISCONNECTED);
+  offliner()->DidFinishNavigation(&handle);
+
   CompleteLoading();
   PumpLoop();
 
@@ -647,12 +647,10 @@
                                       progress_callback()));
 
   // Called after calling LoadAndSave so we have web_contents to work with.
-  std::unique_ptr<content::NavigationHandle> handle(
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          kHttpUrl, offliner()->web_contents()->GetMainFrame(), true,
-          net::Error::OK));
-  // Call DidFinishNavigation with handle.
-  offliner()->DidFinishNavigation(handle.get());
+  content::MockNavigationHandle handle(
+      kHttpUrl, offliner()->web_contents()->GetMainFrame());
+  handle.set_has_committed(true);
+  offliner()->DidFinishNavigation(&handle);
 }
 
 TEST_F(BackgroundLoaderOfflinerTest, OffliningPreviewsStatusOffHistogram) {
@@ -663,22 +661,20 @@
                                       progress_callback()));
 
   // Called after calling LoadAndSave so we have web_contents to work with.
-  std::unique_ptr<content::NavigationHandle> handle(
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          kHttpUrl, offliner()->web_contents()->GetMainFrame(), true,
-          net::Error::OK));
+  content::MockNavigationHandle handle(
+      kHttpUrl, offliner()->web_contents()->GetMainFrame());
+  handle.set_has_committed(true);
   // Set up PreviewsUserData on the handle.
   PreviewsUITabHelper::CreateForWebContents(offliner()->web_contents());
   PreviewsUITabHelper::FromWebContents(offliner()->web_contents())
-      ->CreatePreviewsUserDataForNavigationHandle(handle.get(), 1u)
+      ->CreatePreviewsUserDataForNavigationHandle(&handle, 1u)
       ->set_committed_previews_state(
           content::PreviewsTypes::PREVIEWS_NO_TRANSFORM);
   scoped_refptr<net::HttpResponseHeaders> header(
       new net::HttpResponseHeaders("HTTP/1.1 200 OK"));
-  offliner()->web_contents_tester()->SetHttpResponseHeaders(handle.get(),
-                                                            header);
+  handle.set_response_headers(header.get());
   // Call DidFinishNavigation with handle.
-  offliner()->DidFinishNavigation(handle.get());
+  offliner()->DidFinishNavigation(&handle);
 
   histograms().ExpectBucketCount(
       "OfflinePages.Background.OffliningPreviewStatus.async_loading",
@@ -694,21 +690,20 @@
                                       progress_callback()));
 
   // Called after calling LoadAndSave so we have web_contents to work with.
-  std::unique_ptr<content::NavigationHandle> handle(
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          kHttpUrl, offliner()->web_contents()->GetMainFrame(), true,
-          net::Error::OK));
+  content::MockNavigationHandle handle(
+      kHttpUrl, offliner()->web_contents()->GetMainFrame());
+  handle.set_has_committed(true);
   // Set up PreviewsUserData on the handle.
   PreviewsUITabHelper::CreateForWebContents(offliner()->web_contents());
   PreviewsUITabHelper::FromWebContents(offliner()->web_contents())
-      ->CreatePreviewsUserDataForNavigationHandle(handle.get(), 1u)
+      ->CreatePreviewsUserDataForNavigationHandle(&handle, 1u)
       ->set_committed_previews_state(content::PreviewsTypes::CLIENT_LOFI_ON);
   scoped_refptr<net::HttpResponseHeaders> header(
       new net::HttpResponseHeaders("HTTP/1.1 200 OK"));
-  offliner()->web_contents_tester()->SetHttpResponseHeaders(handle.get(),
-                                                            header);
+  handle.set_response_headers(header.get());
+
   // Call DidFinishNavigation with handle.
-  offliner()->DidFinishNavigation(handle.get());
+  offliner()->DidFinishNavigation(&handle);
 
   histograms().ExpectBucketCount(
       "OfflinePages.Background.OffliningPreviewStatus.async_loading",
diff --git a/chrome/browser/offline_pages/offline_page_url_loader.cc b/chrome/browser/offline_pages/offline_page_url_loader.cc
index 88a03d94..8fe95fcd 100644
--- a/chrome/browser/offline_pages/offline_page_url_loader.cc
+++ b/chrome/browser/offline_pages/offline_page_url_loader.cc
@@ -111,9 +111,8 @@
 }
 
 void OfflinePageURLLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
   NOTREACHED();
 }
diff --git a/chrome/browser/offline_pages/offline_page_url_loader.h b/chrome/browser/offline_pages/offline_page_url_loader.h
index 2ac664e7..4fd73a6 100644
--- a/chrome/browser/offline_pages/offline_page_url_loader.h
+++ b/chrome/browser/offline_pages/offline_page_url_loader.h
@@ -56,11 +56,9 @@
       content::URLLoaderRequestInterceptor::LoaderCallback callback);
 
   // network::mojom::URLLoader:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override;
diff --git a/chrome/browser/plugins/pdf_iframe_navigation_throttle_unittest.cc b/chrome/browser/plugins/pdf_iframe_navigation_throttle_unittest.cc
index 8308b77..1de7b41a1 100644
--- a/chrome/browser/plugins/pdf_iframe_navigation_throttle_unittest.cc
+++ b/chrome/browser/plugins/pdf_iframe_navigation_throttle_unittest.cc
@@ -9,7 +9,7 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
-#include "content/public/browser/navigation_handle.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "net/http/http_util.h"
 #include "ppapi/buildflags/buildflags.h"
 
@@ -83,27 +83,19 @@
   SetAlwaysOpenPdfExternallyForTests(true);
 
   // Never create throttle for main frames.
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(kExampleURL), main_rfh());
-
-  handle->CallWillProcessResponseForTesting(
-      main_rfh(), net::HttpUtil::AssembleRawHeaders(kHeader, strlen(kHeader)),
-      false, net::ProxyServer::Direct());
-
+  std::string raw_response_headers =
+      net::HttpUtil::AssembleRawHeaders(kHeader, strlen(kHeader));
+  scoped_refptr<net::HttpResponseHeaders> headers =
+      new net::HttpResponseHeaders(raw_response_headers);
+  content::MockNavigationHandle handle(GURL(kExampleURL), main_rfh());
+  handle.set_response_headers(headers.get());
   std::unique_ptr<content::NavigationThrottle> throttle =
-      PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(handle.get());
+      PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(&handle);
   ASSERT_EQ(nullptr, throttle);
 
   // Create a throttle for subframes.
-  handle = content::NavigationHandle::CreateNavigationHandleForTesting(
-      GURL(kExampleURL), subframe());
-
-  handle->CallWillProcessResponseForTesting(
-      subframe(), net::HttpUtil::AssembleRawHeaders(kHeader, strlen(kHeader)),
-      false, net::ProxyServer::Direct());
-
-  throttle = PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(handle.get());
+  handle.set_render_frame_host(subframe());
+  throttle = PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(&handle);
   ASSERT_NE(nullptr, throttle);
 }
 
@@ -111,118 +103,91 @@
   // Setup
   SetAlwaysOpenPdfExternallyForTests(true);
 
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(kExampleURL), subframe());
+  std::string raw_response_headers = GetHeaderWithMimeType("application/pdf");
+  raw_response_headers = net::HttpUtil::AssembleRawHeaders(
+      raw_response_headers.c_str(), raw_response_headers.size());
+  scoped_refptr<net::HttpResponseHeaders> headers =
+      new net::HttpResponseHeaders(raw_response_headers);
+  content::MockNavigationHandle handle(GURL(kExampleURL), subframe());
+  handle.set_response_headers(headers.get());
 
   // Verify that we CANCEL for PDF mime type.
-  std::string header = GetHeaderWithMimeType("application/pdf");
-  handle->CallWillProcessResponseForTesting(
-      subframe(),
-      net::HttpUtil::AssembleRawHeaders(header.c_str(), header.size()), false,
-      net::ProxyServer::Direct());
-
   std::unique_ptr<content::NavigationThrottle> throttle =
-      PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(handle.get());
+      PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(&handle);
 
   ASSERT_NE(nullptr, throttle);
   ASSERT_EQ(content::NavigationThrottle::CANCEL_AND_IGNORE,
-            throttle->WillProcessResponse());
+            throttle->WillProcessResponse().action());
 
   // Verify that we PROCEED for other mime types.
   // Blank mime type
-  handle->CallWillProcessResponseForTesting(
-      subframe(), net::HttpUtil::AssembleRawHeaders(kHeader, strlen(kHeader)),
-      false, net::ProxyServer::Direct());
-
-  throttle = PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(handle.get());
-
-  ASSERT_NE(nullptr, throttle);
+  raw_response_headers =
+      net::HttpUtil::AssembleRawHeaders(kHeader, strlen(kHeader));
+  headers = new net::HttpResponseHeaders(raw_response_headers);
+  handle.set_response_headers(headers.get());
   ASSERT_EQ(content::NavigationThrottle::PROCEED,
-            throttle->WillProcessResponse());
+            throttle->WillProcessResponse().action());
 
   // HTML
-  header = GetHeaderWithMimeType("text/html");
-  handle->CallWillProcessResponseForTesting(
-      subframe(),
-      net::HttpUtil::AssembleRawHeaders(header.c_str(), header.size()), false,
-      net::ProxyServer::Direct());
-
-  throttle = PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(handle.get());
-
-  ASSERT_NE(nullptr, throttle);
+  raw_response_headers = GetHeaderWithMimeType("text/html");
+  headers = new net::HttpResponseHeaders(raw_response_headers);
+  handle.set_response_headers(headers.get());
   ASSERT_EQ(content::NavigationThrottle::PROCEED,
-            throttle->WillProcessResponse());
+            throttle->WillProcessResponse().action());
 
   // PNG
-  header = GetHeaderWithMimeType("image/png");
-  handle->CallWillProcessResponseForTesting(
-      subframe(),
-      net::HttpUtil::AssembleRawHeaders(header.c_str(), header.size()), false,
-      net::ProxyServer::Direct());
-
-  throttle = PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(handle.get());
-
-  ASSERT_NE(nullptr, throttle);
+  raw_response_headers = GetHeaderWithMimeType("image/png");
+  headers = new net::HttpResponseHeaders(raw_response_headers);
+  handle.set_response_headers(headers.get());
   ASSERT_EQ(content::NavigationThrottle::PROCEED,
-            throttle->WillProcessResponse());
+            throttle->WillProcessResponse().action());
 }
 
 TEST_F(PDFIFrameNavigationThrottleTest, AllowPDFAttachments) {
   // Setup
   SetAlwaysOpenPdfExternallyForTests(true);
 
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(kExampleURL), subframe());
-
   // Verify that we PROCEED for PDF mime types with an attachment
   // content-disposition.
-  std::string header =
+  std::string raw_response_headers =
       "HTTP/1.1 200 OK\r\n"
       "content-type: application/pdf\r\n"
       "content-disposition: attachment\r\n";
-  handle->CallWillProcessResponseForTesting(
-      subframe(),
-      net::HttpUtil::AssembleRawHeaders(header.c_str(), header.size()), false,
-      net::ProxyServer::Direct());
-
+  scoped_refptr<net::HttpResponseHeaders> headers =
+      new net::HttpResponseHeaders(raw_response_headers);
+  content::MockNavigationHandle handle(GURL(kExampleURL), subframe());
+  handle.set_response_headers(headers.get());
   std::unique_ptr<content::NavigationThrottle> throttle =
-      PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(handle.get());
+      PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(&handle);
 
   ASSERT_NE(nullptr, throttle);
   ASSERT_EQ(content::NavigationThrottle::PROCEED,
-            throttle->WillProcessResponse());
+            throttle->WillProcessResponse().action());
 }
 
 #if BUILDFLAG(ENABLE_PLUGINS)
 TEST_F(PDFIFrameNavigationThrottleTest, CancelOnlyIfPDFViewerIsDisabled) {
   // Setup
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(kExampleURL), subframe());
-
-  std::string header = GetHeaderWithMimeType("application/pdf");
-  handle->CallWillProcessResponseForTesting(
-      subframe(),
-      net::HttpUtil::AssembleRawHeaders(header.c_str(), header.size()), false,
-      net::ProxyServer::Direct());
+  std::string raw_response_headers = GetHeaderWithMimeType("application/pdf");
+  raw_response_headers = net::HttpUtil::AssembleRawHeaders(
+      raw_response_headers.c_str(), raw_response_headers.size());
+  scoped_refptr<net::HttpResponseHeaders> headers =
+      new net::HttpResponseHeaders(raw_response_headers);
+  content::MockNavigationHandle handle(GURL(kExampleURL), subframe());
+  handle.set_response_headers(headers.get());
 
   // Test PDF Viewer enabled.
   SetAlwaysOpenPdfExternallyForTests(false);
-
   std::unique_ptr<content::NavigationThrottle> throttle =
-      PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(handle.get());
-
+      PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(&handle);
   ASSERT_EQ(nullptr, throttle);
 
   // Test PDF Viewer disabled.
   SetAlwaysOpenPdfExternallyForTests(true);
-
-  throttle = PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(handle.get());
+  throttle = PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(&handle);
 
   ASSERT_NE(nullptr, throttle);
   ASSERT_EQ(content::NavigationThrottle::CANCEL_AND_IGNORE,
-            throttle->WillProcessResponse());
+            throttle->WillProcessResponse().action());
 }
 #endif
diff --git a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
index e2b35d9..1bc0785 100644
--- a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
@@ -62,8 +62,8 @@
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/chromeos/policy/user_policy_manager_factory_chromeos.h"
-#include "chromeos/constants/chromeos_paths.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "components/account_id/account_id.h"
 #include "components/user_manager/user_names.h"
@@ -281,8 +281,8 @@
 #if defined(OS_CHROMEOS)
     // Get the path to the user policy key file.
     base::FilePath user_policy_key_dir;
-    ASSERT_TRUE(base::PathService::Get(chromeos::DIR_USER_POLICY_KEYS,
-                                       &user_policy_key_dir));
+    ASSERT_TRUE(base::PathService::Get(
+        chromeos::dbus_paths::DIR_USER_POLICY_KEYS, &user_policy_key_dir));
     std::string sanitized_username =
         chromeos::CryptohomeClient::GetStubSanitizedUsername(
             cryptohome::CreateAccountIdentifierFromAccountId(
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index 7b0c2d6..2b8bd90b 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -3071,11 +3071,9 @@
       : client_(std::move(client)) {}
   ~HangingURLLoader() override {}
   // mojom::URLLoader implementation:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override {}
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override {}
   void ProceedWithResponse() override {}
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override {
diff --git a/chrome/browser/previews/previews_ui_tab_helper_unittest.cc b/chrome/browser/previews/previews_ui_tab_helper_unittest.cc
index 4d451887..19b2e516 100644
--- a/chrome/browser/previews/previews_ui_tab_helper_unittest.cc
+++ b/chrome/browser/previews/previews_ui_tab_helper_unittest.cc
@@ -38,6 +38,7 @@
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/common/previews_state.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/web_contents_tester.h"
 #include "net/http/http_util.h"
 #include "services/network/test/test_shared_url_loader_factory.h"
@@ -60,8 +61,11 @@
 #endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
     MockInfoBarService::CreateForWebContents(web_contents());
     PreviewsUITabHelper::CreateForWebContents(web_contents());
-    test_handle_ = content::NavigationHandle::CreateNavigationHandleForTesting(
+    test_handle_ = std::make_unique<content::MockNavigationHandle>(
         GURL(kTestUrl), main_rfh());
+    std::vector<GURL> redirect_chain;
+    redirect_chain.push_back(GURL(kTestUrl));
+    test_handle_->set_redirect_chain(redirect_chain);
     content::RenderFrameHostTester::For(main_rfh())
         ->InitializeRenderFrameIfNeeded();
 
@@ -105,19 +109,19 @@
   }
 
   void SimulateWillProcessResponse() {
-    std::string headers("HTTP/1.1 200 OK\n\n");
-    test_handle_->CallWillProcessResponseForTesting(
-        main_rfh(),
-        net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()),
-        false, net::ProxyServer::Direct());
     SimulateCommit();
   }
 
   void SimulateCommit() {
-    test_handle_->CallDidCommitNavigationForTesting(GURL(kTestUrl));
+    test_handle_->set_has_committed(true);
+    test_handle_->set_url(GURL(kTestUrl));
   }
 
-  void CallDidFinishNavigation() { test_handle_.reset(); }
+  void CallDidFinishNavigation() {
+    PreviewsUITabHelper* ui_tab_helper =
+        PreviewsUITabHelper::FromWebContents(web_contents());
+    ui_tab_helper->DidFinishNavigation(test_handle_.get());
+  }
 
   previews::PreviewsUserData* CreatePreviewsUserData(int64_t page_id) {
     PreviewsUITabHelper* ui_tab_helper =
@@ -135,7 +139,7 @@
       drp_test_context_;
 
  private:
-  std::unique_ptr<content::NavigationHandle> test_handle_;
+  std::unique_ptr<content::MockNavigationHandle> test_handle_;
 };
 
 TEST_F(PreviewsUITabHelperUnitTest, DidFinishNavigationCreatesLitePageInfoBar) {
diff --git a/chrome/browser/resource_coordinator/background_tab_navigation_throttle_unittest.cc b/chrome/browser/resource_coordinator/background_tab_navigation_throttle_unittest.cc
index c78a7f61..13e0f11 100644
--- a/chrome/browser/resource_coordinator/background_tab_navigation_throttle_unittest.cc
+++ b/chrome/browser/resource_coordinator/background_tab_navigation_throttle_unittest.cc
@@ -12,9 +12,9 @@
 #include "chrome/browser/ui/tab_ui_helper.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/variations/variations_associated_data.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/navigation_throttle.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/web_contents_tester.h"
 #include "url/gurl.h"
 
@@ -106,10 +106,9 @@
     rfh = content::RenderFrameHostTester::For(main_rfh())->AppendChild("child");
 
   DCHECK(rfh);
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(url_, rfh);
+  content::MockNavigationHandle handle(url_, rfh);
   std::unique_ptr<BackgroundTabNavigationThrottle> throttle =
-      BackgroundTabNavigationThrottle::MaybeCreateThrottleFor(handle.get());
+      BackgroundTabNavigationThrottle::MaybeCreateThrottleFor(&handle);
 
   const bool expect_instantiation =
       expected_instantiation_result_ == EXPECT_INSTANTIATION;
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_webcontents_observer_unittest.cc b/chrome/browser/resource_coordinator/local_site_characteristics_webcontents_observer_unittest.cc
index 4c15d6d..a8897f6 100644
--- a/chrome/browser/resource_coordinator/local_site_characteristics_webcontents_observer_unittest.cc
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_webcontents_observer_unittest.cc
@@ -13,9 +13,9 @@
 #include "chrome/browser/resource_coordinator/site_characteristics_data_store.h"
 #include "chrome/browser/resource_coordinator/tab_manager_features.h"
 #include "chrome/browser/resource_coordinator/time.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/favicon_url.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/web_contents_tester.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -160,10 +160,9 @@
 
   // Navigate to a different origin but don't set the |committed| bit, this
   // shouldn't affect the writer.
-  auto navigation_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          kTestUrl2, web_contents()->GetMainFrame(), false);
-  observer()->DidFinishNavigation(navigation_handle.get());
+  content::MockNavigationHandle navigation_handle(
+      kTestUrl2, web_contents()->GetMainFrame());
+  observer()->DidFinishNavigation(&navigation_handle);
   ::testing::Mock::VerifyAndClear(mock_writer);
 
   // Set the |committed| bit and ensure that the navigation event cause the
diff --git a/chrome/browser/resource_coordinator/tab_manager_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
index 37a4207..29978a8 100644
--- a/chrome/browser/resource_coordinator/tab_manager_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -49,6 +49,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/web_contents_tester.h"
 #include "net/base/network_change_notifier.h"
@@ -56,7 +57,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-using content::NavigationHandle;
+using content::MockNavigationHandle;
 using content::NavigationThrottle;
 using content::WebContents;
 using content::WebContentsTester;
@@ -164,14 +165,23 @@
   }
 
   void ResetState() {
+    // Simulate the DidFinishNavigation notification coming from the
+    // NavigationHandles.
+    if (nav_handle1_)
+      tab_manager_->OnDidFinishNavigation(nav_handle1_.get());
+    if (nav_handle2_)
+      tab_manager_->OnDidFinishNavigation(nav_handle2_.get());
+    if (nav_handle3_)
+      tab_manager_->OnDidFinishNavigation(nav_handle3_.get());
+
     // NavigationHandles and NavigationThrottles must be deleted before the
     // associated WebContents.
-    nav_handle1_.reset();
-    nav_handle2_.reset();
-    nav_handle3_.reset();
     throttle1_.reset();
     throttle2_.reset();
     throttle3_.reset();
+    nav_handle1_.reset();
+    nav_handle2_.reset();
+    nav_handle3_.reset();
 
     // WebContents must be deleted before
     // ChromeTestHarnessWithLocalDB::TearDown() deletes the
@@ -283,12 +293,12 @@
   }
 
  protected:
-  std::unique_ptr<NavigationHandle> CreateTabAndNavigation(
+  std::unique_ptr<MockNavigationHandle> CreateTabAndNavigation(
       const char* url,
       content::WebContents* web_contents) {
     TabUIHelper::CreateForWebContents(web_contents);
-    return content::NavigationHandle::CreateNavigationHandleForTesting(
-        GURL(url), web_contents->GetMainFrame());
+    return std::make_unique<MockNavigationHandle>(GURL(url),
+                                                  web_contents->GetMainFrame());
   }
 
   TabManager* tab_manager_ = nullptr;
@@ -299,9 +309,9 @@
   std::unique_ptr<BackgroundTabNavigationThrottle> throttle1_;
   std::unique_ptr<BackgroundTabNavigationThrottle> throttle2_;
   std::unique_ptr<BackgroundTabNavigationThrottle> throttle3_;
-  std::unique_ptr<NavigationHandle> nav_handle1_;
-  std::unique_ptr<NavigationHandle> nav_handle2_;
-  std::unique_ptr<NavigationHandle> nav_handle3_;
+  std::unique_ptr<MockNavigationHandle> nav_handle1_;
+  std::unique_ptr<MockNavigationHandle> nav_handle2_;
+  std::unique_ptr<MockNavigationHandle> nav_handle3_;
   std::unique_ptr<WebContents> contents1_;
   std::unique_ptr<WebContents> contents2_;
   std::unique_ptr<WebContents> contents3_;
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
index ecbaa8f..970d4cc 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -1369,11 +1369,11 @@
   });
 });
 
-TEST_F('ChromeVoxBackgroundTest', 'TextSelectionAndLiveRegion', function() {
+// Failing consistently, please see https://crbug.com/857382
+TEST_F('ChromeVoxBackgroundTest', 'DISABLED_TextSelectionAndLiveRegion', function() {
   DesktopAutomationHandler.announceActions = true;
   var mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(function(root) {/*!
-    <p>start</p>
     <div><input value="test" type="text"></input></div>
     <div id="live" aria-live="assertive"></div>
     <script>
@@ -1383,13 +1383,11 @@
       div.addEventListener('click', function() {
         clicks++;
         if (clicks == 1) {
-          live.textContent = 'go';
-        } else if (clicks == 2) {
           input.selectionStart = 1;
           live.textContent = 'queued';
         } else {
-          input.selectionStart = 2;
           live.textContent = 'interrupted';
+          input.selectionStart = 2;
         }
       });
     </script>
@@ -1399,15 +1397,12 @@
     mockFeedback.call(textField.focus.bind(textField))
         .expectSpeech('Edit text')
         .call(div.doDefault.bind(div))
-        .expectSpeechWithQueueMode('go', cvox.QueueMode.CATEGORY_FLUSH)
-
-        .call(div.doDefault.bind(div))
         .expectSpeechWithQueueMode('e', cvox.QueueMode.FLUSH)
-        .expectSpeechWithQueueMode('queued', cvox.QueueMode.QUEUE)
+        .expectSpeechWithQueueMode('queued', cvox.QueueMode.CATEGORY_FLUSH)
 
         .call(div.doDefault.bind(div))
-        .expectSpeechWithQueueMode('s', cvox.QueueMode.FLUSH)
         .expectSpeechWithQueueMode('interrupted', cvox.QueueMode.QUEUE)
+        .expectSpeechWithQueueMode('s', cvox.QueueMode.FLUSH)
 
         .replay();
   });
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
index 9bfe601..eeeb708 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
@@ -702,13 +702,6 @@
     return this.value.length;
   },
 
-  /** @override */
-  changed: function(evt) {
-    // This path does not use the Output module to synthesize speech.
-    Output.forceModeForNextSpeechUtterance(undefined);
-    cvox.ChromeVoxEditableTextBase.prototype.changed.call(this, evt);
-  },
-
   /**
    * @private
    * @param {editing.EditableLine} cur Current line.
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions.js
index 5e283ddc..09b67ba 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions.js
@@ -87,10 +87,8 @@
   onTreeChange: function(treeChange) {
     var type = treeChange.type;
     var node = treeChange.target;
-    if ((!node.containerLiveStatus || node.containerLiveStatus == 'off') &&
-        type != TreeChangeType.SUBTREE_UPDATE_END) {
+    if (!node.containerLiveStatus && type != TreeChangeType.SUBTREE_UPDATE_END)
       return;
-    }
 
     var currentRange = this.chromeVoxState_.currentRange;
 
@@ -142,15 +140,11 @@
    * @private
    */
   processQueuedTreeChanges_: function() {
-    // Schedule all live regions after all events in the native C++ EventBundle.
     this.liveRegionNodeSet_ = new WeakSet();
-    setTimeout(function() {
-      for (var i = 0; i < this.changedNodes_.length; i++) {
-        var node = this.changedNodes_[i];
-        this.outputLiveRegionChange_(node, null);
-      }
-      this.changedNodes_ = [];
-    }.bind(this), 0);
+    this.changedNodes_.forEach(function(node) {
+      this.outputLiveRegionChange_(node, null);
+    }.bind(this));
+    this.changedNodes_ = [];
   },
 
   /**
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions_test.extjs
index 592fbe8..fd26ae0 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions_test.extjs
@@ -167,7 +167,8 @@
     function(rootNode) {
       var go = rootNode.find({ role: RoleType.BUTTON });
       mockFeedback.call(go.doDefault.bind(go))
-          .expectCategoryFlushSpeech('After');
+          .expectCategoryFlushSpeech('After')
+          .expectQueuedSpeech('Image');
       mockFeedback.replay();
     });
 });
@@ -294,9 +295,7 @@
     var live = new LiveRegions(ChromeVoxState.instance);
     var t1, t2;
     [t1, t2] = root.findAll({role: RoleType.STATIC_TEXT});
-    mockFeedback.expectSpeech('hello there')
-        .clearPendingOutput()
-        .call(function() {
+    mockFeedback.call(function() {
           live.onTreeChange({type: TreeChangeType.TEXT_CHANGED, target: t2});
           live.onTreeChange({type: TreeChangeType.SUBTREE_UPDATE_END, target: t2});
         })
@@ -313,39 +312,3 @@
     mockFeedback.replay();
   });
 });
-
-TEST_F('ChromeVoxLiveRegionsTest', 'LiveStatusOff', function() {
-  var mockFeedback = this.createMockFeedback();
-  this.runWithLoadedTree(function() {/*!
-    <div><input aria-live="off" type="text"></input></div>
-    <script>
-      var input = document.querySelector('input');
-      var div = document.querySelector('div');
-      var clicks = 0;
-      div.addEventListener('click', () => {
-        clicks++;
-        if (clicks == 1) {
-          input.value = 'bb';
-          input.selectionStart = 2;
-          input.selectionEnd = 2;
-        } else if (clicks == 2) {
-          input.value = 'bba';
-          input.selectionStart = 3;
-          input.selectionEnd = 3;
-        }
-      });
-    </script>
-  */},
-  function(root) {
-    var input = root.find({role: RoleType.TEXT_FIELD});
-    var clickInput = input.parent.doDefault.bind(input.parent);
-    mockFeedback.call(input.focus.bind(input))
-        .call(clickInput)
-        .expectSpeech('bb')
-        .clearPendingOutput()
-        .call(clickInput)
-        .expectNextSpeechUtteranceIsNot('bba')
-        .expectSpeech('a')
-        .replay();
-  });
-});
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
index 1b1de4f..331455c 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
@@ -708,7 +708,7 @@
  * Calling this will make the next speech utterance use |mode| even if it would
  * normally queue or do a category flush. This differs from the |withQueueMode|
  * instance method as it can apply to future output.
- * @param {cvox.QueueMode|undefined} mode
+ * @param {cvox.QueueMode} mode
  */
 Output.forceModeForNextSpeechUtterance = function(mode) {
   Output.forceModeForNextSpeechUtterance_ = mode;
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd
index 5edb0d4a..d5dae760 100644
--- a/chrome/browser/resources/component_extension_resources.grd
+++ b/chrome/browser/resources/component_extension_resources.grd
@@ -124,6 +124,8 @@
           <include name="IDR_PDF_VIEWER_INK_INK_API_JS" file="pdf/ink/ink_api.js" type="BINDATA" />
           <include name="IDR_PDF_VIEWER_INK_HOST_HTML" file="pdf/elements/viewer-ink-host/viewer-ink-host.html" type="BINDATA" />
           <include name="IDR_PDF_VIEWER_INK_HOST_JS" file="pdf/elements/viewer-ink-host/viewer-ink-host.js" type="BINDATA" />
+          <include name="IDR_PDF_VIEWER_PEN_OPTIONS_HTML" file="pdf/elements/viewer-pen-options/viewer-pen-options.html" type="BINDATA" />
+          <include name="IDR_PDF_VIEWER_PEN_OPTIONS_JS" file="pdf/elements/viewer-pen-options/viewer-pen-options.js" type="BINDATA" />
         </if>
         <include name="IDR_PDF_VIEWER_PAGE_INDICATOR_HTML" file="pdf/elements/viewer-page-indicator/viewer-page-indicator.html" type="BINDATA" />
         <include name="IDR_PDF_VIEWER_PAGE_INDICATOR_JS" file="pdf/elements/viewer-page-indicator/viewer-page-indicator.js" type="BINDATA" flattenhtml="true" />
@@ -131,7 +133,7 @@
         <include name="IDR_PDF_VIEWER_PAGE_SELECTOR_JS" file="pdf/elements/viewer-page-selector/viewer-page-selector.js" type="BINDATA" />
         <include name="IDR_PDF_VIEWER_PASSWORD_SCREEN_HTML" file="pdf/elements/viewer-password-screen/viewer-password-screen.html" type="BINDATA" />
         <include name="IDR_PDF_VIEWER_PASSWORD_SCREEN_JS" file="pdf/elements/viewer-password-screen/viewer-password-screen.js" type="BINDATA" />
-        <include name="IDR_PDF_VIEWER_PDF_TOOLBAR_HTML" file="pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html" type="BINDATA" />
+        <include name="IDR_PDF_VIEWER_PDF_TOOLBAR_HTML" file="pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html" type="BINDATA" preprocess="true" />
         <include name="IDR_PDF_VIEWER_PDF_TOOLBAR_JS" file="pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js" type="BINDATA" />
         <include name="IDR_PDF_VIEWER_TOOLBAR_DROPDOWN_HTML" file="pdf/elements/viewer-toolbar-dropdown/viewer-toolbar-dropdown.html" type="BINDATA" />
         <include name="IDR_PDF_VIEWER_TOOLBAR_DROPDOWN_JS" file="pdf/elements/viewer-toolbar-dropdown/viewer-toolbar-dropdown.js" type="BINDATA" />
diff --git a/chrome/browser/resources/pdf/elements/icons.html b/chrome/browser/resources/pdf/elements/icons.html
index 99295a3..f71953e 100644
--- a/chrome/browser/resources/pdf/elements/icons.html
+++ b/chrome/browser/resources/pdf/elements/icons.html
@@ -12,7 +12,10 @@
       <g id="bookmark"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2z"></path></g>
       <g id="bookmark-border"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2zm0 15l-5-2.18L7 18V5h10v13z"></path></g>
       <g id="create"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path></g>
+      <g id="eraser"><path d="m15.543 4.9863c-0.32193 0.019835-0.65088 0.1626-0.91016 0.42188l-4.8867 4.8867 5.5332 5.5332h-2.1211l-4.4727-4.4727-0.65234 0.65234c-0.51854 0.51855-0.56773 1.319-0.10938 1.7773l4.166 4.166c0.45836 0.45836 1.2588 0.40917 1.7773-0.10938l6.5996-6.5996c0.51854-0.51855 0.56773-1.319 0.10938-1.7773l-4.166-4.166c-0.22918-0.22918-0.54525-0.33233-0.86719-0.3125zm-12.543 13.764v1.5h0.75 6 0.75v-1.5h-0.75-6-0.75z"></path></g>
       <g id="fullscreen-exit"><path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"></path></g>
+      <g id="highlighter"><path d="M15.7498169,15.9885 L18.69405,19.7475 C18.75405,19.8165 18.79455,19.89975 18.8148,19.98825 C17.22405,20.30025 14.37105,20.25 12.0648,20.25 C9.72705,20.25 6.61248962,20.295 5.01423962,19.9755 C5.03523962,19.8915 5.07348962,19.8135 5.13123962,19.7475 L8.25498962,15.9885 L8.25498962,11.3135317 C8.25498962,11.2722817 8.26398962,11.2317817 8.28123962,11.1957817 L8.59698962,10.5297817 C8.59698962,10.5 15.4078169,10.49925 15.4078169,10.5 L15.7235669,11.1957817 C15.7400669,11.2317817 15.7498169,11.2722817 15.7498169,11.3135317 L15.7498169,15.9885"></path><path d="M13.846962,4.03912354 L14.04,4.09664481 C14.163,4.13093052 14.25,4.25693052 14.25,4.40178767 L14.25,5.43243216 L14.25,5.7872893 L14.25,8.82657296 C13.6995,8.91057296 12.79575,9 12,9 C11.20275,9 10.3005,8.91057296 9.75,8.82571582 L9.75,4.41586073 L9.75,3.85871787 L9.75,3.3152893 C9.75,3.11043216 9.91725,2.96043216 10.09125,3.0092893 L13.846962,4.03912354 Z" style="fill: var(--pen-tip-fill)"></g>
+      <g id="marker"><path d="M14.25,8.91853902 L14.25,6.53925711 C14.25,5.97869512 14.1161242,5.42520919 13.8582163,4.92039274 L12.7090497,2.67089612 C12.4225948,2.10981636 11.5774052,2.10964378 11.2909503,2.67072353 C10.911176,3.41422755 10.4575732,4.30184157 10.1413899,4.92108308 C9.88348208,5.42589953 9.75,5.97869512 9.75,6.53925711 L9.75,8.91940195 C10.4758827,8.97169576 11.2816971,9 11.9916328,9 C12.7058997,9 13.5195892,8.97152317 14.25,8.91853902" style="fill: var(--pen-tip-fill)"></path><path d="M15.7498169,15.9885 L15.7498169,11.3135317 C15.7498169,11.2722817 15.7400669,11.2317817 15.7235669,11.1957817 L15.4078169,10.5 C15.4078169,10.49925 8.59698962,10.5 8.59698962,10.5297817 L8.28123962,11.1957817 C8.26398962,11.2317817 8.25498962,11.2722817 8.25498962,11.3135317 L8.25498962,15.9885 L5.13123962,19.7475 C5.07348962,19.8135 5.03523962,19.8915 5.01423962,19.9755 C6.61248962,20.295 9.72705,20.25 12.0648,20.25 C14.37105,20.25 17.22405,20.30025 18.8148,19.98825 C18.79455,19.89975 18.75405,19.8165 18.69405,19.7475 L15.7498169,15.9885 Z"></path></g>
       <g id="remove"><path d="M19 13H5v-2h14v2z"></path></g>
       <g id="rotate-right"><path d="M15.55 5.55L11 1v3.07C7.06 4.56 4 7.92 4 12s3.05 7.44 7 7.93v-2.02c-2.84-.48-5-2.94-5-5.91s2.16-5.43 5-5.91V10l4.55-4.45zM19.93 11c-.17-1.39-.72-2.73-1.62-3.89l-1.42 1.42c.54.75.88 1.6 1.02 2.47h2.02zM13 17.9v2.02c1.39-.17 2.74-.71 3.9-1.61l-1.44-1.44c-.75.54-1.59.89-2.46 1.03zm3.89-2.42l1.42 1.41c.9-1.16 1.45-2.5 1.62-3.89h-2.02c-.14.87-.48 1.72-1.02 2.48z"></path></g>
     </defs>
diff --git a/chrome/browser/resources/pdf/elements/viewer-ink-host/viewer-ink-host.js b/chrome/browser/resources/pdf/elements/viewer-ink-host/viewer-ink-host.js
index ba34d0e..8913ca8 100644
--- a/chrome/browser/resources/pdf/elements/viewer-ink-host/viewer-ink-host.js
+++ b/chrome/browser/resources/pdf/elements/viewer-ink-host/viewer-ink-host.js
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/** @enum {string} */
 const State = {
   LOADING: 'loading',
   ACTIVE: 'active',
@@ -21,6 +22,17 @@
   /** @private {?string} */
   fileName_: null,
 
+  /** @private {State} */
+  state_: State.IDLE,
+
+  /** @param {AnnotationTool} tool */
+  setAnnotationTool(tool) {
+    this.tool_ = tool;
+    if (this.state_ == State.ACTIVE) {
+      this.ink_.setAnnotationTool(tool);
+    }
+  },
+
   /**
    * Begins annotation mode with the document represented by `data`.
    * When the return value resolves the Ink component will be ready
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
index 5eda02d..f2bb7eed 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
+++ b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
@@ -5,6 +5,9 @@
 <link rel="import" href="../icons.html">
 <link rel="import" href="../viewer-bookmarks-content/viewer-bookmarks-content.html">
 <link rel="import" href="../viewer-page-selector/viewer-page-selector.html">
+<if expr="chromeos">
+<link rel="import" href="../viewer-pen-options/viewer-pen-options.html">
+</if>
 <link rel="import" href="../viewer-toolbar-dropdown/viewer-toolbar-dropdown.html">
 
 <dom-module id="viewer-pdf-toolbar">
@@ -65,6 +68,17 @@
       #toolbar {
         @apply --shadow-elevation-2dp;
         background-color: rgb(50, 54, 57);
+        position: relative;
+      }
+
+      #annotations-bar {
+        align-items: center;
+        background-color: rgb(32, 33, 34);
+        justify-content: center;
+      }
+
+      #toolbar,
+      #annotations-bar {
         color: rgb(241, 241, 241);
         display: flex;
         height: 48px;
@@ -81,6 +95,12 @@
         width: auto;
       }
 
+      #pen,
+      #highlighter {
+        --dropdown-width: 346px;
+      }
+
+
       .invisible {
         visibility: hidden;
       }
@@ -164,6 +184,45 @@
         <paper-progress id="progress" value="[[loadProgress]]"></paper-progress>
       </div>
     </div>
+
+    <div id="annotations-bar" class="invisible">
+      <paper-icon-button id="eraser"
+          on-click="annotationToolClicked_"
+          icon="pdf:eraser"
+          aria-label$="{{strings.tooltipEraser}}"
+          title$="{{strings.tooltipEraser}}">
+      </paper-icon-button>
+
+      <viewer-toolbar-dropdown id="pen"
+          on-click="annotationToolClicked_"
+          open-icon="pdf:marker"
+          closed-icon="pdf:marker"
+          dropdown-centered
+          style="--pen-tip-fill: #000000">
+        <viewer-pen-options
+          selected-color="#000000"
+          selected-size="0.1429"
+          strings="[[strings]]"
+          on-selected-size-changed="annotationToolOptionChanged_"
+          on-selected-color-changed="annotationToolOptionChanged_">
+        </viewer-pen-options>
+      </viewer-toolbar-dropdown>
+
+      <viewer-toolbar-dropdown id="highlighter"
+          on-click="annotationToolClicked_"
+          open-icon="pdf:highlighter"
+          closed-icon="pdf:highlighter"
+          dropdown-centered
+          style="--pen-tip-fill: #ffbc00">
+        <viewer-pen-options
+          selected-color="#ffbc00"
+          selected-size="0.7143"
+          strings="[[strings]]"
+          on-selected-size-changed="annotationToolOptionChanged_"
+          on-selected-color-changed="annotationToolOptionChanged_">
+        </viewer-pen-options>
+      </viewer-toolbar-dropdown>
+    </div>
   </template>
   <script src="viewer-pdf-toolbar.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
index aa7d9a8..6e9fe18 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
+++ b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
@@ -42,6 +42,13 @@
     annotationMode: {
       type: Boolean,
       notify: true,
+      value: false,
+    },
+
+    annotationTool: {
+      type: Object,
+      value: null,
+      notify: true,
     },
 
     /**
@@ -64,11 +71,13 @@
       this.$.pageselector.classList.toggle('invisible', !loaded);
       this.$.buttons.classList.toggle('invisible', !loaded);
       this.$.progress.style.opacity = loaded ? 0 : 1;
+      this.$['annotations-bar'].classList.toggle(
+          'invisible', !(loaded && this.annotationMode));
     }
   },
 
   hide: function() {
-    if (this.opened) {
+    if (this.opened && !this.shouldKeepOpen()) {
       this.toggleVisibility();
     }
   },
@@ -117,15 +126,24 @@
 
   shouldKeepOpen: function() {
     return this.$.bookmarks.dropdownOpen || this.loadProgress < 100 ||
-        this.$.pageselector.isActive();
+        this.$.pageselector.isActive() || this.annotationMode;
   },
 
   hideDropdowns: function() {
+    let result = false;
     if (this.$.bookmarks.dropdownOpen) {
       this.$.bookmarks.toggleDropdown();
-      return true;
+      result = true;
     }
-    return false;
+    if (this.$.pen.dropdownOpen) {
+      this.$.pen.toggleDropdown();
+      result = true;
+    }
+    if (this.$.highlighter.dropdownOpen) {
+      this.$.highlighter.toggleDropdown();
+      result = true;
+    }
+    return result;
   },
 
   setDropdownLowerBound: function(lowerBound) {
@@ -146,6 +164,40 @@
 
   toggleAnnotation: function() {
     this.annotationMode = !this.annotationMode;
+    if (this.annotationMode) {
+      // Select pen tool when entering annotation mode.
+      this.updateAnnotationTool_(this.$.pen);
+    }
+  },
+
+  /** @param {Event} e */
+  annotationToolClicked_: function(e) {
+    this.updateAnnotationTool_(e.currentTarget);
+
+  },
+
+  /** @param {Event} e */
+  annotationToolOptionChanged_: function(e) {
+    const element = e.currentTarget.parentElement;
+    if (!this.annotationTool || element.id != this.annotationTool.tool) {
+      return;
+    }
+    this.updateAnnotationTool_(e.currentTarget.parentElement);
+  },
+
+  /** @param {Element} element */
+  updateAnnotationTool_: function(element) {
+    const tool = element.id;
+    const options = element.querySelector('viewer-pen-options') || {
+      selectedSize: 1,
+      selectedColor: null,
+    };
+    element.attributeStyleMap.set('--pen-tip-fill', options.selectedColor);
+    this.annotationTool = {
+      tool: tool,
+      size: options.selectedSize,
+      color: options.selectedColor,
+    };
   }
 });
 })();
diff --git a/chrome/browser/resources/pdf/elements/viewer-pen-options/BUILD.gn b/chrome/browser/resources/pdf/elements/viewer-pen-options/BUILD.gn
new file mode 100644
index 0000000..b542932
--- /dev/null
+++ b/chrome/browser/resources/pdf/elements/viewer-pen-options/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+  deps = [
+    ":viewer-pen-options",
+  ]
+}
+
+js_library("viewer-pen-options") {
+}
diff --git a/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.html b/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.html
new file mode 100644
index 0000000..068e4d60
--- /dev/null
+++ b/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.html
@@ -0,0 +1,90 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
+
+<dom-module id="viewer-pen-options">
+  <template>
+    <style>
+    #colors,
+    #sizes {
+      display: grid;
+      grid-gap: 20px 10px;
+      grid-template-columns: repeat(8, 1fr);
+      margin: 10px;
+    }
+    #colors {
+      overflow: hidden;
+    }
+    input,
+    #expand {
+      height: 32px;
+      width: 32px;
+    }
+    #expand {
+      grid-column: 8;
+      grid-row: 1 / 4;
+    }
+    input {
+      -webkit-appearance: none;
+      border-radius: 16px;
+      margin: 0;
+      padding: 0;
+
+    }
+    #sizes input {
+      background: black;
+      border: calc(15px - 13px * var(--item-size)) solid white;
+      position: relative;
+    }
+    #sizes input:hover {
+      box-shadow: 0 0 0 1px silver;
+    }
+    #sizes input[checked] {
+      box-shadow: 0 0 0 1px black;
+    }
+    #colors input {
+      background: var(--item-color, magenta);
+      transition: transform 300ms;
+      transform: scale(0.625)
+    }
+    #colors input:hover {
+      transform: scale(0.8125);
+    }
+    #colors input[checked] {
+      transform: scale(1);
+    }
+    #colors input[outline] {
+      border: 1px solid silver;
+    }
+    #separator {
+      background: silver;
+      height: 1px;
+    }
+    </style>
+    <div id="colors" on-change="colorChanged_" expanded$="[[expanded_]]">
+      <template is="dom-repeat" items="[[colors_]]">
+        <input type="radio" name="color" value="[[item.color]]"
+            outline$="[[item.outline]]"
+            checked$="[[equal_(selectedColor, item.color)]]"
+            tabindex="1" style="--item-color: [[item.color]]"
+            aria-label$="[[lookup_(strings, item.name)]]">
+      </template>
+      <paper-icon-button id="expand" icon="cr:expand-more"
+          tabindex="3"
+          on-click="toggleExpanded_"
+          aria-label$="[[strings.tooltipExpand]]"
+          title$="[[strings.tooltipExpand]]">
+      </paper-icon-button>
+    </div>
+    <div id="separator"></div>
+    <div id="sizes" on-change="sizeChanged_">
+      <template is="dom-repeat" items="[[sizes_]]">
+        <input type="radio" name="size" value="[[item.size]]"
+            checked$="[[equal_(selectedSize, item.size)]]"
+            tabindex="2" style="--item-size: [[item.size]]"
+            aria-label$="[[lookup_(strings, item.name)]]">
+      </template>
+    </div>
+    </paper-icon-button>
+  </template>
+  <script src="viewer-pen-options.js"></script>
+</dom-module>
\ No newline at end of file
diff --git a/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.js b/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.js
new file mode 100644
index 0000000..e01a3886
--- /dev/null
+++ b/chrome/browser/resources/pdf/elements/viewer-pen-options/viewer-pen-options.js
@@ -0,0 +1,174 @@
+// 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.
+
+const colors = [
+  // row 1
+  {name: 'annotationColorBlack', color: '#000000'},
+  {name: 'annotationColorRed', color: '#ff5252'},
+  {name: 'annotationColorYellow', color: '#ffbc00'},
+  {name: 'annotationColorGreen', color: '#00c853'},
+  {name: 'annotationColorCyan', color: '#00b0ff'},
+  {name: 'annotationColorPurple', color: '#d500f9'},
+  {name: 'annotationColorBrown', color: '#8d6e63'},
+  // row 2
+  {name: 'annotationColorWhite', color: '#fafafa', outline: true},
+  {name: 'annotationColorCrimson', color: '#a52714'},
+  {name: 'annotationColorAmber', color: '#ee8100'},
+  {name: 'annotationColorAvocadoGreen', color: '#558b2f'},
+  {name: 'annotationColorCobaltBlue', color: '#01579b'},
+  {name: 'annotationColorDeepPurple', color: '#8e24aa'},
+  {name: 'annotationColorDarkBrown', color: '#4e342e'},
+  // row 3
+  {name: 'annotationColorDarkGrey', color: '#90a4ae'},
+  {name: 'annotationColorHotPink', color: '#ff4081'},
+  {name: 'annotationColorOrange', color: '#ff6e40'},
+  {name: 'annotationColorLime', color: '#aeea00'},
+  {name: 'annotationColorBlue', color: '#304ffe'},
+  {name: 'annotationColorViolet', color: '#7c4dff'},
+  {name: 'annotationColorTeal', color: '#1de9b6'},
+  // row 4
+  {name: 'annotationColorLightGrey', color: '#cfd8dc'},
+  {name: 'annotationColorLightPink', color: '#f8bbd0'},
+  {name: 'annotationColorLightOrange', color: '#ffccbc'},
+  {name: 'annotationColorLightGreen', color: '#f0f4c3'},
+  {name: 'annotationColorLightBlue', color: '#9fa8da'},
+  {name: 'annotationColorLavender', color: '#d1c4e9'},
+  {name: 'annotationColorLightTeal', color: '#b2dfdb'},
+];
+
+const sizes = [
+  {name: 'annotationSize1', size: 0},
+  {name: 'annotationSize2', size: 0.1429},
+  {name: 'annotationSize3', size: 0.2857},
+  {name: 'annotationSize4', size: 0.4286},
+  {name: 'annotationSize8', size: 0.5714},
+  {name: 'annotationSize12', size: 0.7143},
+  {name: 'annotationSize16', size: 0.8571},
+  {name: 'annotationSize20', size: 1},
+];
+
+/**
+ * Displays a set of radio buttons to select from
+ * a predefined list of colors and sizes.
+ */
+Polymer({
+  is: 'viewer-pen-options',
+
+  properties: {
+    expanded_: {
+      type: Boolean,
+      value: false,
+    },
+    selectedSize: {
+      type: Number,
+      value: 0.250,
+      notify: true,
+    },
+    selectedColor: {
+      type: String,
+      value: '#000000',
+      notify: true,
+    },
+    sizes_: {
+      type: Array,
+      value: sizes,
+    },
+    colors_: {
+      type: Array,
+      value: colors,
+    },
+    strings: Object,
+  },
+
+  /** @type {Array<Animation>} */
+  expandAnimations_: null,
+
+  /** @param {Event} e */
+  sizeChanged_: function(e) {
+    this.selectedSize = Number(e.target.value);
+  },
+
+  /** @param {Event} e */
+  colorChanged_: function(e) {
+    this.selectedColor = e.target.value;
+  },
+
+  toggleExpanded_: function() {
+    this.expanded_ = !this.expanded_;
+    this.updateExpandedState_();
+  },
+
+  attached() {
+    this.updateExpandedState_();
+    for (const animation of this.expandAnimations_) {
+      animation.finish();
+    }
+  },
+
+  /**
+   * Updates the state of the UI to reflect the current value of `expanded`.
+   * Starts or reverses animations and enables/disable controls.
+   */
+  updateExpandedState_: function() {
+    const colors = this.$.colors;
+    if (!this.expandAnimations_) {
+      const separator = this.$.separator;
+      const expand = this.$.expand;
+      this.expandAnimations_ = [
+        colors.animate({height: ['32px', '188px']}, {
+          easing: 'ease-in-out',
+          duration: 250,
+          fill: 'both',
+        }),
+        separator.animate({opacity: [0, 1]}, {
+          easing: 'ease-in-out',
+          duration: 250,
+          fill: 'both',
+        }),
+        expand.animate({transform: ['rotate(0deg)', 'rotate(180deg)']}, {
+          easing: 'ease-in-out',
+          duration: 250,
+          fill: 'forwards',
+        }),
+      ];
+    }
+    if (this.expanded_) {
+      for (const animation of this.expandAnimations_) {
+        animation.playbackRate = 1;
+      }
+    } else {
+      for (const animation of this.expandAnimations_) {
+        animation.playbackRate = -1;
+      }
+    }
+    for (const input of colors.querySelectorAll('input:nth-child(n+8)')) {
+      if (this.expanded_) {
+        input.removeAttribute('disabled');
+      } else {
+        input.setAttribute('disabled', '');
+      }
+    }
+  },
+
+  /**
+   * Used to determine equality in computed bindings.
+   *
+   * @param {*} a
+   * @param {*} b
+   */
+  equal_: function(a,b) {
+    return a == b;
+  },
+
+  /**
+   * Used to lookup a string in a computed binding.
+   *
+   * @param {Object} strings
+   * @param {string} name
+   * @return {string}
+   */
+  lookup_: function(strings, name) {
+    return strings[name];
+  }
+});
\ No newline at end of file
diff --git a/chrome/browser/resources/pdf/ink/ink_api.js b/chrome/browser/resources/pdf/ink/ink_api.js
index efe9c7a..eee18a53 100644
--- a/chrome/browser/resources/pdf/ink/ink_api.js
+++ b/chrome/browser/resources/pdf/ink/ink_api.js
@@ -3,6 +3,15 @@
 // found in the LICENSE file.
 
 /**
+ * @typedef {{
+ *   tool: string,
+ *   size: number,
+ *   color: string,
+ * }}
+ */
+let AnnotationTool;
+
+/**
  * Wraps the Ink component with an API that can be called
  * across an IFrame boundary.
  */
@@ -32,6 +41,12 @@
   setCamera(camera) {
     this.embed_.setCamera(camera);
   }
+
+  /** @param {AnnotationTool} tool */
+  setAnnotationTool(tool) {
+    // TODO(dstockwell): Use Ink api to convert `tool` to `Brush`
+    this.embed_.setTool(tool);
+  }
 }
 
 /**
@@ -39,6 +54,9 @@
  */
 window.initInk = function() {
   // TODO(dstockwell): Create real Ink embed and pass to InkAPI.
-  const embed = {setCamera() {}};
+  const embed = {
+    setCamera: function() {},
+    setTool: function() {},
+  };
   return new InkAPI(embed);
 };
\ No newline at end of file
diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js
index 33c6f94..4a4d0645 100644
--- a/chrome/browser/resources/pdf/pdf_viewer.js
+++ b/chrome/browser/resources/pdf/pdf_viewer.js
@@ -256,6 +256,9 @@
         'rotate-right', () => this.currentController_.rotateClockwise());
     this.toolbar_.addEventListener(
         'annotation-mode-changed', e => this.annotationModeChanged_(e));
+    this.toolbar_.addEventListener(
+        'annotation-tool-changed',
+        e => this.inkController_.setAnnotationTool(e.detail.value));
 
     this.toolbar_.docTitle = getFilenameFromURL(this.originalUrl_);
   }
@@ -503,6 +506,7 @@
       // TODO(dstockwell): feed real progress data from the Ink component
       this.updateProgress(50);
       await this.inkController_.load(result.fileName, result.dataToSave);
+      this.inkController_.setAnnotationTool(this.toolbar_.annotationTool);
       this.currentController_ = this.inkController_;
       this.pluginController_.unload();
       this.updateProgress(100);
@@ -1205,6 +1209,14 @@
     this.inkHost_ = null;
   }
 
+  /** @param {AnnotationTool} tool */
+  setAnnotationTool(tool) {
+    this.tool_ = tool;
+    if (this.inkHost_) {
+      this.inkHost_.setAnnotationTool(tool);
+    }
+  }
+
   /** @override */
   rotateClockwise() {
     // TODO(dstockwell): implement rotation
diff --git a/chrome/browser/resources/print_preview/data/cloud_parsers.js b/chrome/browser/resources/print_preview/data/cloud_parsers.js
index 2648923..4069b25 100644
--- a/chrome/browser/resources/print_preview/data/cloud_parsers.js
+++ b/chrome/browser/resources/print_preview/data/cloud_parsers.js
@@ -111,7 +111,7 @@
     const optionalParams = {
       account: account,
       tags: tags,
-      isOwned: tags.includes(OWNED_TAG),
+      isOwned: arrayContains(tags, OWNED_TAG),
       lastAccessTime:
           parseInt(json[CloudDestinationField.LAST_ACCESS], 10) || Date.now(),
       cloudID: id,
@@ -121,7 +121,7 @@
     const cloudDest = new print_preview.Destination(
         id, parseType(json[CloudDestinationField.TYPE]), origin,
         json[CloudDestinationField.DISPLAY_NAME],
-        tags.includes(RECENT_TAG) /*isRecent*/, connectionStatus,
+        arrayContains(tags, RECENT_TAG) /*isRecent*/, connectionStatus,
         optionalParams);
     if (json.hasOwnProperty(CloudDestinationField.CAPABILITIES)) {
       cloudDest.capabilities = /** @type {!print_preview.Cdd} */ (
diff --git a/chrome/browser/resources/print_preview/data/destination.js b/chrome/browser/resources/print_preview/data/destination.js
index 6b0cfaec..5580239c5 100644
--- a/chrome/browser/resources/print_preview/data/destination.js
+++ b/chrome/browser/resources/print_preview/data/destination.js
@@ -607,10 +607,12 @@
 
     /** @return {boolean} Whether the destination is considered offline. */
     get isOffline() {
-      return [
-        print_preview.DestinationConnectionStatus.OFFLINE,
-        print_preview.DestinationConnectionStatus.DORMANT
-      ].includes(this.connectionStatus_);
+      return arrayContains(
+          [
+            print_preview.DestinationConnectionStatus.OFFLINE,
+            print_preview.DestinationConnectionStatus.DORMANT
+          ],
+          this.connectionStatus_);
     }
 
     /**
diff --git a/chrome/browser/resources/print_preview/data/destination_match.js b/chrome/browser/resources/print_preview/data/destination_match.js
index e30339c..be030065 100644
--- a/chrome/browser/resources/print_preview/data/destination_match.js
+++ b/chrome/browser/resources/print_preview/data/destination_match.js
@@ -51,17 +51,16 @@
     }
 
     /**
-     * @param {!print_preview.DestinationOrigin} origin Origin to match.
+     * @param {string} origin Origin to match.
      * @return {boolean} Whether the origin is one of the {@code origins_}.
      */
     matchOrigin(origin) {
-      return this.origins_.includes(origin);
+      return arrayContains(this.origins_, origin);
     }
 
     /**
      * @param {string} id Id of the destination.
-     * @param {!print_preview.DestinationOrigin} origin Origin of the
-     *     destination.
+     * @param {string} origin Origin of the destination.
      * @return {boolean} Whether destination is the same as initial.
      */
     matchIdAndOrigin(id, origin) {
@@ -99,11 +98,13 @@
      * @private
      */
     isVirtualDestination_(destination) {
-      if (destination.origin === print_preview.DestinationOrigin.LOCAL) {
-        return destination.id ===
-            print_preview.Destination.GooglePromotedId.SAVE_AS_PDF;
+      if (destination.origin == print_preview.DestinationOrigin.LOCAL) {
+        return arrayContains(
+            [print_preview.Destination.GooglePromotedId.SAVE_AS_PDF],
+            destination.id);
       }
-      return destination.id === print_preview.Destination.GooglePromotedId.DOCS;
+      return arrayContains(
+          [print_preview.Destination.GooglePromotedId.DOCS], destination.id);
     }
 
     /**
diff --git a/chrome/browser/resources/print_preview/new/advanced_settings_dialog.js b/chrome/browser/resources/print_preview/new/advanced_settings_dialog.js
index 73c239f..65904e9 100644
--- a/chrome/browser/resources/print_preview/new/advanced_settings_dialog.js
+++ b/chrome/browser/resources/print_preview/new/advanced_settings_dialog.js
@@ -91,8 +91,8 @@
       item.hidden = !matches;
       hasMatch = hasMatch || matches;
       const result = item.updateHighlighting(this.searchQuery_);
-      this.highlights_.push.apply(this.highlights_, result.highlights);
-      this.bubbles_.push.apply(this.bubbles_, result.bubbles);
+      this.highlights_.push(...result.highlights);
+      this.bubbles_.push(...result.bubbles);
     });
     return hasMatch;
   },
diff --git a/chrome/browser/resources/print_preview/print_preview_utils.js b/chrome/browser/resources/print_preview/print_preview_utils.js
index a17e8f62..7fbc963 100644
--- a/chrome/browser/resources/print_preview/print_preview_utils.js
+++ b/chrome/browser/resources/print_preview/print_preview_utils.js
@@ -3,9 +3,46 @@
 // found in the LICENSE file.
 
 /**
+ * @param {string} toTest The string to be tested.
+ * @return {boolean} True if |toTest| contains only digits. Leading and trailing
+ *     whitespace is allowed.
+ */
+function isInteger(toTest) {
+  const numericExp = /^\s*[0-9]+\s*$/;
+  return numericExp.test(toTest);
+}
+
+/**
+ * Returns true if |value| is a valid non zero positive integer.
+ * @param {string} value The string to be tested.
+ * @return {boolean} true if the |value| is valid non zero positive integer.
+ */
+function isPositiveInteger(value) {
+  return isInteger(value) && parseInt(value, 10) > 0;
+}
+
+/**
+ * Returns true if the contents of the two arrays are equal.
+ * @param {Array<{from: number, to: number}>} array1 The first array.
+ * @param {Array<{from: number, to: number}>} array2 The second array.
+ * @return {boolean} true if the arrays are equal.
+ */
+function areArraysEqual(array1, array2) {
+  if (array1.length != array2.length) {
+    return false;
+  }
+  for (let i = 0; i < array1.length; i++) {
+    if (array1[i] !== array2[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+/**
  * Returns true if the contents of the two page ranges are equal.
- * @param {!Array<{ to: number, from: number }>} array1 The first array.
- * @param {!Array<{ to: number, from: number }>} array2 The second array.
+ * @param {Array} array1 The first array.
+ * @param {Array} array2 The second array.
  * @return {boolean} true if the arrays are equal.
  */
 function areRangesEqual(array1, array2) {
@@ -21,6 +58,179 @@
 }
 
 /**
+ * Removes duplicate elements from |inArray| and returns a new array.
+ * |inArray| is not affected. It assumes that |inArray| is already sorted.
+ * @param {!Array<number>} inArray The array to be processed.
+ * @return {!Array<number>} The array after processing.
+ */
+function removeDuplicates(inArray) {
+  const out = [];
+
+  if (inArray.length == 0) {
+    return out;
+  }
+
+  out.push(inArray[0]);
+  for (let i = 1; i < inArray.length; ++i) {
+    if (inArray[i] != inArray[i - 1]) {
+      out.push(inArray[i]);
+    }
+  }
+  return out;
+}
+
+/** @enum {number} */
+const PageRangeStatus = {
+  NO_ERROR: 0,
+  SYNTAX_ERROR: -1,
+  LIMIT_ERROR: -2
+};
+
+/**
+ * Returns a list of ranges in |pageRangeText|. The ranges are
+ * listed in the order they appear in |pageRangeText| and duplicates are not
+ * eliminated. If |pageRangeText| is not valid, PageRangeStatus.SYNTAX_ERROR
+ * is returned.
+ * A valid selection has a parsable format and every page identifier is
+ * greater than 0 unless wildcards are used(see examples).
+ * If a page is greater than |totalPageCount|, PageRangeStatus.LIMIT_ERROR
+ * is returned.
+ * If |totalPageCount| is 0 or undefined function uses impossibly large number
+ * instead.
+ * Wildcard the first number must be larger than 0 and less or equal then
+ * |totalPageCount|. If it's missed then 1 is used as the first number.
+ * Wildcard the second number must be larger then the first number. If it's
+ * missed then |totalPageCount| is used as the second number.
+ * Example: "1-4, 9, 3-6, 10, 11" is valid, assuming |totalPageCount| >= 11.
+ * Example: "1-4, -6" is valid, assuming |totalPageCount| >= 6.
+ * Example: "2-" is valid, assuming |totalPageCount| >= 2, means from 2 to the
+ *          end.
+ * Example: "4-2, 11, -6" is invalid.
+ * Example: "-" is valid, assuming |totalPageCount| >= 1.
+ * Example: "1-4dsf, 11" is invalid regardless of |totalPageCount|.
+ * @param {string} pageRangeText The text to be checked.
+ * @param {number=} opt_totalPageCount The total number of pages.
+ * @return {!PageRangeStatus|!Array<{from: number, to: number}>}
+ */
+function pageRangeTextToPageRanges(pageRangeText, opt_totalPageCount) {
+  if (pageRangeText == '') {
+    return [];
+  }
+
+  const MAX_PAGE_NUMBER = 1000000000;
+  const totalPageCount =
+      opt_totalPageCount ? opt_totalPageCount : MAX_PAGE_NUMBER;
+
+  const regex = /^\s*([0-9]*)\s*-\s*([0-9]*)\s*$/;
+  const parts = pageRangeText.split(/,|\u3001/);
+
+  const pageRanges = [];
+  for (let i = 0; i < parts.length; ++i) {
+    const match = parts[i].match(regex);
+    if (match) {
+      if (!isPositiveInteger(match[1]) && match[1] !== '') {
+        return PageRangeStatus.SYNTAX_ERROR;
+      }
+      if (!isPositiveInteger(match[2]) && match[2] !== '') {
+        return PageRangeStatus.SYNTAX_ERROR;
+      }
+      const from = match[1] ? parseInt(match[1], 10) : 1;
+      const to = match[2] ? parseInt(match[2], 10) : totalPageCount;
+      if (from > to) {
+        return PageRangeStatus.SYNTAX_ERROR;
+      }
+      if (to > totalPageCount) {
+        return PageRangeStatus.LIMIT_ERROR;
+      }
+      pageRanges.push({'from': from, 'to': to});
+    } else {
+      if (!isPositiveInteger(parts[i])) {
+        return PageRangeStatus.SYNTAX_ERROR;
+      }
+      const singlePageNumber = parseInt(parts[i], 10);
+      if (singlePageNumber > totalPageCount) {
+        return PageRangeStatus.LIMIT_ERROR;
+      }
+      pageRanges.push({'from': singlePageNumber, 'to': singlePageNumber});
+    }
+  }
+  return pageRanges;
+}
+
+/**
+ * Returns a list of pages defined by |pagesRangeText|. The pages are
+ * listed in the order they appear in |pageRangeText| and duplicates are not
+ * eliminated. If |pageRangeText| is not valid according or
+ * |totalPageCount| undefined [1,2,...,totalPageCount] is returned.
+ * See pageRangeTextToPageRanges for details.
+ * @param {string} pageRangeText The text to be checked.
+ * @param {number} totalPageCount The total number of pages.
+ * @return {!Array<number>} A list of all pages.
+ */
+function pageRangeTextToPageList(pageRangeText, totalPageCount) {
+  const pageRanges = pageRangeTextToPageRanges(pageRangeText, totalPageCount);
+  const pageList = [];
+  if (Array.isArray(pageRanges)) {
+    for (let i = 0; i < pageRanges.length; ++i) {
+      for (let j = pageRanges[i].from;
+           j <= Math.min(pageRanges[i].to, totalPageCount); ++j) {
+        pageList.push(j);
+      }
+    }
+  }
+  if (pageList.length == 0) {
+    for (let j = 1; j <= totalPageCount; ++j) {
+      pageList.push(j);
+    }
+  }
+  return pageList;
+}
+
+/**
+ * @param {!Array<number>} pageList The list to be processed.
+ * @return {!Array<number>} The contents of |pageList| in ascending order and
+ *     without any duplicates. |pageList| is not affected.
+ */
+function pageListToPageSet(pageList) {
+  let pageSet = [];
+  if (pageList.length == 0) {
+    return pageSet;
+  }
+  pageSet = pageList.slice(0);
+  pageSet.sort(function(a, b) {
+    return /** @type {number} */ (a) - /** @type {number} */ (b);
+  });
+  pageSet = removeDuplicates(pageSet);
+  return pageSet;
+}
+
+/**
+ * @param {!HTMLElement} element Element to check for visibility.
+ * @return {boolean} Whether the given element is visible.
+ */
+function getIsVisible(element) {
+  return !element.hidden;
+}
+
+/**
+ * Shows or hides an element.
+ * @param {!HTMLElement} element Element to show or hide.
+ * @param {boolean} isVisible Whether the element should be visible or not.
+ */
+function setIsVisible(element, isVisible) {
+  element.hidden = !isVisible;
+}
+
+/**
+ * @param {!Array} array Array to check for item.
+ * @param {*} item Item to look for in array.
+ * @return {boolean} Whether the item is in the array.
+ */
+function arrayContains(array, item) {
+  return array.indexOf(item) != -1;
+}
+
+/**
  * @param {!Array<!{locale: string, value: string}>} localizedStrings An array
  *     of strings with corresponding locales.
  * @param {string} locale Locale to look the string up for.
diff --git a/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs b/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs
new file mode 100644
index 0000000..17fa25be
--- /dev/null
+++ b/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs
@@ -0,0 +1,139 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * Test fixture for print preview utils.
+ * @constructor
+ * @extends {testing.Test}
+ */
+function PrintPreviewUtilsUnitTest () {
+  testing.Test.call(this);
+}
+
+PrintPreviewUtilsUnitTest.prototype = {
+  __proto__: testing.Test.prototype,
+
+  /** @override */
+  extraLibraries: [
+    'print_preview_utils.js',
+  ]
+};
+
+TEST_F('PrintPreviewUtilsUnitTest', 'IsInteger', function() {
+  assertFalse(isInteger("  abc "));
+  assertFalse(isInteger("-7"));
+  assertFalse(isInteger("7.0"));
+  assertFalse(isInteger("a7a"));
+
+  assertTrue(isInteger("0"));
+  assertTrue(isInteger(" 100  "));
+  assertTrue(isInteger("0055 "));
+});
+
+TEST_F('PrintPreviewUtilsUnitTest', 'IsPositiveInteger', function() {
+  assertTrue(isPositiveInteger("100"));
+  assertTrue(isPositiveInteger("0055"));
+
+  assertFalse(isPositiveInteger("0"));
+  assertFalse(isPositiveInteger("-100"));
+  assertFalse(isPositiveInteger("sdfs"));
+});
+
+TEST_F('PrintPreviewUtilsUnitTest', 'AreArraysEqual', function() {
+  assertTrue(areArraysEqual([2,4,6,8,10], [2,4,6,8,10]));
+  assertTrue(areArraysEqual([], []));
+
+  assertFalse(areArraysEqual([2,4,6,8,10,12], [2,4,6,8,10]));
+  assertFalse(areArraysEqual([], [2,4,6,8,10]));
+});
+
+TEST_F('PrintPreviewUtilsUnitTest', 'RemoveDuplicates', function() {
+  var array1 = [1,2,2,3,6,6,6,7,9,10];
+  assertTrue(areArraysEqual(removeDuplicates(array1), [1,2,3,6,7,9,10]));
+});
+
+TEST_F('PrintPreviewUtilsUnitTest', 'PageRanges', function() {
+  function assertRangesEqual(simpleRange1, range2) {
+    var range1 = []
+    for (var i = 0; i < simpleRange1.length; i++) {
+      var from;
+      var to;
+      if (Array.isArray(simpleRange1[i])) {
+        from = simpleRange1[i][0];
+        to = simpleRange1[i][1];
+      } else {
+        from = simpleRange1[i];
+        to = simpleRange1[i];
+      }
+      range1.push({'from': from, 'to': to});
+    }
+    assertTrue(areRangesEqual(range1, range2));
+  };
+  assertRangesEqual([1, 2, 3, 1, 56],
+                    pageRangeTextToPageRanges("1,2,3,1,56", 100));
+  assertRangesEqual([[1, 3],[6, 9], [6, 10]],
+                    pageRangeTextToPageRanges("1-3, 6-9,6-10 ", 100));
+  assertRangesEqual([[10, 100]],
+                    pageRangeTextToPageRanges("10-", 100));
+  assertRangesEqual([[10, 100000]],
+                    pageRangeTextToPageRanges("10-100000", 100000));
+  assertRangesEqual([[1, 100]],
+                    pageRangeTextToPageRanges("-", 100));
+  assertRangesEqual([1, 2],
+                    pageRangeTextToPageRanges("1,2", undefined));
+  assertRangesEqual([[1, 1000000000]],
+                    pageRangeTextToPageRanges("-", null));
+  assertRangesEqual([[1, 1000000000]],
+                    pageRangeTextToPageRanges("-", 0));
+
+  // https://crbug.com/806165
+  assertRangesEqual([1, 2, 3, 1, 56],
+                    pageRangeTextToPageRanges("1\u30012\u30013\u30011\u300156", 100));
+  assertRangesEqual([1, 2, 3, 1, 56],
+                    pageRangeTextToPageRanges("1,2,3\u30011\u300156", 100));
+});
+
+TEST_F('PrintPreviewUtilsUnitTest', 'InvalidPageRanges', function() {
+  assertEquals(PageRangeStatus.LIMIT_ERROR,
+      pageRangeTextToPageRanges("10-100000", 100));
+  assertEquals(PageRangeStatus.LIMIT_ERROR,
+      pageRangeTextToPageRanges("1,100000", 100));
+  assertEquals(PageRangeStatus.SYNTAX_ERROR,
+      pageRangeTextToPageRanges("1,2,0,56", 100));
+  assertEquals(PageRangeStatus.SYNTAX_ERROR,
+      pageRangeTextToPageRanges("-1,1,2,,56", 100));
+  assertEquals(PageRangeStatus.SYNTAX_ERROR,
+      pageRangeTextToPageRanges("1,2,56-40", 100));
+  assertEquals(PageRangeStatus.LIMIT_ERROR,
+      pageRangeTextToPageRanges("101-110", 100));
+
+  assertEquals(PageRangeStatus.SYNTAX_ERROR,
+      pageRangeTextToPageRanges("1\u30012\u30010\u300156", 100));
+  assertEquals(PageRangeStatus.SYNTAX_ERROR,
+      pageRangeTextToPageRanges("-1,1,2\u3001\u300156", 100));
+});
+
+TEST_F('PrintPreviewUtilsUnitTest', 'PageRangeTextToPageList', function() {
+  assertTrue(areArraysEqual([1],
+                            pageRangeTextToPageList("1", 10)));
+  assertTrue(areArraysEqual([1,2,3,4],
+                            pageRangeTextToPageList("1-4", 10)));
+  assertTrue(areArraysEqual([1,2,3,4,2,3,4],
+                            pageRangeTextToPageList("1-4, 2-4", 10)));
+  assertTrue(areArraysEqual([1,2,5,7,8,9,10,2,2,3],
+                            pageRangeTextToPageList("1-2, 5, 7-10, 2, 2, 3",
+                                                    10)));
+  assertTrue(areArraysEqual([5,6,7,8,9,10],
+                            pageRangeTextToPageList("5-", 10)));
+  assertTrue(areArraysEqual([],
+                            pageRangeTextToPageList("1-4", undefined)));
+  assertTrue(areArraysEqual([1,2,3,4,5,6,7,8,9,10],
+                            pageRangeTextToPageList("1-abcd", 10)));
+});
+
+TEST_F('PrintPreviewUtilsUnitTest', 'PageListToPageSet', function() {
+  assertTrue(areArraysEqual([1,2,3,4], pageListToPageSet([4,3,2,1,1,1])));
+  assertTrue(areArraysEqual([1,2,3,4], pageListToPageSet([1,2,2,3,4,1,1,1])));
+  assertTrue(areArraysEqual([], pageListToPageSet([])));
+});
diff --git a/chrome/browser/resources/settings/search_settings.js b/chrome/browser/resources/settings/search_settings.js
index f8f4381a..1d3cc52 100644
--- a/chrome/browser/resources/settings/search_settings.js
+++ b/chrome/browser/resources/settings/search_settings.js
@@ -434,8 +434,8 @@
      * @param {!Array<!Node>} bubbles The search bubbles to add.
      */
     addHighlightsAndBubbles(highlights, bubbles) {
-      this.highlights_.push.apply(this.highlights_, highlights);
-      this.bubbles_.push.apply(this.bubbles_, bubbles);
+      this.highlights_.push(...highlights);
+      this.bubbles_.push(...bubbles);
     }
 
     removeAllTextObservers() {
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
index aab7b39a..e4713e6 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -40,6 +40,7 @@
 #include "components/variations/variations_params_manager.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/browser/test_event_router.h"
 #include "net/http/http_util.h"
@@ -69,7 +70,6 @@
 const char kPasswordReuseURL[] = "http://login.example.com/";
 const char kTestEmail[] = "foo@example.com";
 const char kTestGmail[] = "foo@gmail.com";
-const char kBasicResponseHeaders[] = "HTTP/1.1 200 OK";
 const char kRedirectURL[] = "http://redirect.com";
 
 BrowserContextKeyedServiceFactory::TestingFactory
@@ -273,16 +273,6 @@
     service_->pending_requests_.insert(request_);
   }
 
-  content::NavigationThrottle::ThrottleCheckResult SimulateWillStart(
-      content::NavigationHandle* test_handle) {
-    std::unique_ptr<PasswordProtectionNavigationThrottle> throttle =
-        service_->MaybeCreateNavigationThrottle(test_handle);
-    if (throttle)
-      test_handle->RegisterThrottleForTesting(std::move(throttle));
-
-    return test_handle->CallWillStartRequestForTesting();
-  }
-
   int GetSizeofUnhandledSyncPasswordReuses() {
     DictionaryPrefUpdate unhandled_sync_password_reuses(
         profile()->GetPrefs(), prefs::kSafeBrowsingUnhandledSyncPasswordReuses);
@@ -867,11 +857,10 @@
                  PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN,
                  /*is_warning_showing=*/false);
   GURL redirect_url(kRedirectURL);
-  std::unique_ptr<content::NavigationHandle> test_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(redirect_url,
-                                                                  main_rfh());
-  EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            SimulateWillStart(test_handle.get()));
+  content::MockNavigationHandle test_handle(redirect_url, main_rfh());
+  std::unique_ptr<PasswordProtectionNavigationThrottle> throttle =
+      service_->MaybeCreateNavigationThrottle(&test_handle);
+  EXPECT_EQ(nullptr, throttle);
 }
 
 TEST_F(ChromePasswordProtectionServiceTest,
@@ -885,29 +874,26 @@
                  /*is_warning_showing=*/false);
 
   GURL redirect_url(kRedirectURL);
-  std::unique_ptr<content::NavigationHandle> test_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(redirect_url,
-                                                                  main_rfh());
+  bool was_navigation_resumed = false;
+  content::MockNavigationHandle test_handle(redirect_url, main_rfh());
+  std::unique_ptr<PasswordProtectionNavigationThrottle> throttle =
+      service_->MaybeCreateNavigationThrottle(&test_handle);
+  ASSERT_NE(nullptr, throttle);
+  throttle->set_resume_callback_for_testing(
+      base::BindLambdaForTesting([&]() { was_navigation_resumed = true; }));
+
   // Verify navigation get deferred.
-  EXPECT_EQ(content::NavigationThrottle::DEFER,
-            SimulateWillStart(test_handle.get()));
-  EXPECT_FALSE(test_handle->HasCommitted());
+  EXPECT_EQ(content::NavigationThrottle::DEFER, throttle->WillStartRequest());
   base::RunLoop().RunUntilIdle();
 
   // Simulate receiving a SAFE verdict.
   SimulateRequestFinished(LoginReputationClientResponse::SAFE);
   base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(true, was_navigation_resumed);
 
   // Verify that navigation can be resumed.
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            test_handle->CallWillProcessResponseForTesting(
-                main_rfh(),
-                net::HttpUtil::AssembleRawHeaders(
-                    kBasicResponseHeaders, strlen(kBasicResponseHeaders)),
-                false, net::ProxyServer::Direct()));
-  test_handle->CallDidCommitNavigationForTesting(redirect_url);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(test_handle->HasCommitted());
+            throttle->WillProcessResponse());
 }
 
 TEST_F(ChromePasswordProtectionServiceTest,
@@ -926,13 +912,12 @@
   base::RunLoop().RunUntilIdle();
 
   GURL redirect_url(kRedirectURL);
-  std::unique_ptr<content::NavigationHandle> test_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(redirect_url,
-                                                                  main_rfh());
+  content::MockNavigationHandle test_handle(redirect_url, main_rfh());
+  std::unique_ptr<PasswordProtectionNavigationThrottle> throttle =
+      service_->MaybeCreateNavigationThrottle(&test_handle);
+
   // Verify that navigation gets canceled.
-  EXPECT_EQ(content::NavigationThrottle::CANCEL,
-            SimulateWillStart(test_handle.get()));
-  EXPECT_FALSE(test_handle->HasCommitted());
+  EXPECT_EQ(content::NavigationThrottle::CANCEL, throttle->WillStartRequest());
 }
 
 TEST_F(ChromePasswordProtectionServiceTest,
@@ -946,17 +931,17 @@
                  /*is_warning_showing=*/false);
 
   GURL redirect_url(kRedirectURL);
-  std::unique_ptr<content::NavigationHandle> test_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(redirect_url,
-                                                                  main_rfh());
+  content::MockNavigationHandle test_handle(redirect_url, main_rfh());
+  std::unique_ptr<PasswordProtectionNavigationThrottle> throttle =
+      service_->MaybeCreateNavigationThrottle(&test_handle);
+
   // Verify navigation get deferred.
-  EXPECT_EQ(content::NavigationThrottle::DEFER,
-            SimulateWillStart(test_handle.get()));
+  EXPECT_EQ(content::NavigationThrottle::DEFER, throttle->WillStartRequest());
 
   EXPECT_EQ(1u, GetNumberOfNavigationThrottles());
 
-  // Simulate the deletion of NavigationHandle.
-  test_handle.reset();
+  // Simulate the deletion of the PasswordProtectionNavigationThrottle.
+  throttle.reset();
   base::RunLoop().RunUntilIdle();
 
   // Expect no navigation throttle kept by |request_|.
diff --git a/chrome/browser/signin/account_investigator_factory.cc b/chrome/browser/signin/account_investigator_factory.cc
index 8ff4a48..457f666 100644
--- a/chrome/browser/signin/account_investigator_factory.cc
+++ b/chrome/browser/signin/account_investigator_factory.cc
@@ -6,7 +6,6 @@
 
 #include "base/memory/singleton.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/gaia_cookie_manager_service_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/pref_registry/pref_registry_syncable.h"
@@ -30,7 +29,6 @@
     : BrowserContextKeyedServiceFactory(
           "AccountInvestigator",
           BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(GaiaCookieManagerServiceFactory::GetInstance());
   DependsOn(IdentityManagerFactory::GetInstance());
 }
 
@@ -40,7 +38,6 @@
     content::BrowserContext* context) const {
   Profile* profile(Profile::FromBrowserContext(context));
   AccountInvestigator* investigator = new AccountInvestigator(
-      GaiaCookieManagerServiceFactory::GetForProfile(profile),
       profile->GetPrefs(), IdentityManagerFactory::GetForProfile(profile));
   investigator->Initialize();
   return investigator;
diff --git a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
index 601e04a64..5c03bfd3 100644
--- a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
+++ b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
@@ -101,10 +101,9 @@
   }
 
   // network::mojom::URLLoader:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>& to_be_removed_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
 
   void ProceedWithResponse() override { target_loader_->ProceedWithResponse(); }
 
@@ -190,15 +189,15 @@
   ProxyRequestAdapter(InProgressRequest* in_progress_request,
                       const net::HttpRequestHeaders& original_headers,
                       net::HttpRequestHeaders* modified_headers,
-                      std::vector<std::string>* headers_to_remove)
+                      std::vector<std::string>* removed_headers)
       : ChromeRequestAdapter(nullptr),
         in_progress_request_(in_progress_request),
         original_headers_(original_headers),
         modified_headers_(modified_headers),
-        headers_to_remove_(headers_to_remove) {
+        removed_headers_(removed_headers) {
     DCHECK(in_progress_request_);
     DCHECK(modified_headers_);
-    DCHECK(headers_to_remove_);
+    DCHECK(removed_headers_);
   }
 
   ~ProxyRequestAdapter() override = default;
@@ -233,12 +232,12 @@
   bool HasHeader(const std::string& name) override {
     return (original_headers_.HasHeader(name) ||
             modified_headers_->HasHeader(name)) &&
-           !base::ContainsValue(*headers_to_remove_, name);
+           !base::ContainsValue(*removed_headers_, name);
   }
 
   void RemoveRequestHeaderByName(const std::string& name) override {
-    if (!base::ContainsValue(*headers_to_remove_, name))
-      headers_to_remove_->push_back(name);
+    if (!base::ContainsValue(*removed_headers_, name))
+      removed_headers_->push_back(name);
   }
 
   void SetExtraHeaderByName(const std::string& name,
@@ -246,16 +245,16 @@
     modified_headers_->SetHeader(name, value);
 
     auto it =
-        std::find(headers_to_remove_->begin(), headers_to_remove_->end(), name);
-    if (it != headers_to_remove_->end())
-      headers_to_remove_->erase(it);
+        std::find(removed_headers_->begin(), removed_headers_->end(), name);
+    if (it != removed_headers_->end())
+      removed_headers_->erase(it);
   }
 
  private:
   InProgressRequest* const in_progress_request_;
   const net::HttpRequestHeaders& original_headers_;
-  net::HttpRequestHeaders* const modified_headers_;
-  std::vector<std::string>* const headers_to_remove_;
+  net::HttpRequestHeaders* modified_headers_;
+  std::vector<std::string>* removed_headers_;
 
   DISALLOW_COPY_AND_ASSIGN(ProxyRequestAdapter);
 };
@@ -325,12 +324,12 @@
   client_binding_.Bind(mojo::MakeRequest(&proxy_client));
 
   net::HttpRequestHeaders modified_headers;
-  std::vector<std::string> headers_to_remove;
+  std::vector<std::string> removed_headers;
   ProxyRequestAdapter adapter(this, request.headers, &modified_headers,
-                              &headers_to_remove);
+                              &removed_headers);
   factory_->delegate_->ProcessRequest(&adapter, GURL() /* redirect_url */);
 
-  if (modified_headers.IsEmpty() && headers_to_remove.empty()) {
+  if (modified_headers.IsEmpty() && removed_headers.empty()) {
     factory_->target_factory_->CreateLoaderAndStart(
         mojo::MakeRequest(&target_loader_), routing_id, request_id, options,
         request, std::move(proxy_client), traffic_annotation);
@@ -341,7 +340,7 @@
   } else {
     network::ResourceRequest request_copy = request;
     request_copy.headers.MergeFrom(modified_headers);
-    for (const std::string& name : headers_to_remove)
+    for (const std::string& name : removed_headers)
       request_copy.headers.RemoveHeader(name);
 
     factory_->target_factory_->CreateLoaderAndStart(
@@ -359,31 +358,21 @@
 }
 
 void ProxyingURLLoaderFactory::InProgressRequest::FollowRedirect(
-    const base::Optional<std::vector<std::string>>& opt_headers_to_remove,
-    const base::Optional<net::HttpRequestHeaders>& opt_modified_headers,
+    const std::vector<std::string>& removed_headers_ext,
+    const net::HttpRequestHeaders& modified_headers_ext,
     const base::Optional<GURL>& opt_new_url) {
-  std::vector<std::string> headers_to_remove;
-  if (opt_headers_to_remove)
-    headers_to_remove = *opt_headers_to_remove;
-
-  net::HttpRequestHeaders modified_headers;
-  if (opt_modified_headers)
-    modified_headers.CopyFrom(*opt_modified_headers);
-
+  std::vector<std::string> removed_headers = removed_headers_ext;
+  net::HttpRequestHeaders modified_headers = modified_headers_ext;
   ProxyRequestAdapter adapter(this, headers_, &modified_headers,
-                              &headers_to_remove);
+                              &removed_headers);
   factory_->delegate_->ProcessRequest(&adapter, redirect_info_.new_url);
 
   headers_.MergeFrom(modified_headers);
-  for (const std::string& name : headers_to_remove)
+  for (const std::string& name : removed_headers)
     headers_.RemoveHeader(name);
 
-  target_loader_->FollowRedirect(
-      headers_to_remove.empty() ? base::nullopt
-                                : base::make_optional(headers_to_remove),
-      modified_headers.IsEmpty() ? base::nullopt
-                                 : base::make_optional(modified_headers),
-      opt_new_url);
+  target_loader_->FollowRedirect(removed_headers, modified_headers,
+                                 opt_new_url);
 
   request_url_ = redirect_info_.new_url;
   referrer_origin_ = GURL(redirect_info_.new_referrer).GetOrigin();
diff --git a/chrome/browser/signin/dice_response_handler_unittest.cc b/chrome/browser/signin/dice_response_handler_unittest.cc
index 6ff7c2d8..6a48564 100644
--- a/chrome/browser/signin/dice_response_handler_unittest.cc
+++ b/chrome/browser/signin/dice_response_handler_unittest.cc
@@ -103,15 +103,14 @@
                         &token_service_,
                         &account_tracker_service_,
                         nullptr),
-        signin_error_controller_(
-            SigninErrorController::AccountMode::PRIMARY_ACCOUNT,
-            &token_service_,
-            &signin_manager_),
         cookie_service_(&token_service_, &signin_client_),
         identity_test_env_(&account_tracker_service_,
                            &token_service_,
                            &signin_manager_,
                            &cookie_service_),
+        signin_error_controller_(
+            SigninErrorController::AccountMode::PRIMARY_ACCOUNT,
+            identity_test_env_.identity_manager()),
         about_signin_internals_(&token_service_,
                                 &account_tracker_service_,
                                 identity_test_env_.identity_manager(),
@@ -207,9 +206,9 @@
   FakeProfileOAuth2TokenService token_service_;
   AccountTrackerService account_tracker_service_;
   FakeSigninManager signin_manager_;
-  SigninErrorController signin_error_controller_;
   FakeGaiaCookieManagerService cookie_service_;
   identity::IdentityTestEnvironment identity_test_env_;
+  SigninErrorController signin_error_controller_;
   AboutSigninInternals about_signin_internals_;
   std::unique_ptr<AccountReconcilor> account_reconcilor_;
   std::unique_ptr<DiceResponseHandler> dice_response_handler_;
diff --git a/chrome/browser/signin/signin_error_controller_factory.cc b/chrome/browser/signin/signin_error_controller_factory.cc
index f3df088f..40c3943 100644
--- a/chrome/browser/signin/signin_error_controller_factory.cc
+++ b/chrome/browser/signin/signin_error_controller_factory.cc
@@ -7,19 +7,15 @@
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/signin/core/browser/account_consistency_method.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_manager.h"
 
 SigninErrorControllerFactory::SigninErrorControllerFactory()
     : BrowserContextKeyedServiceFactory(
           "SigninErrorController",
           BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
-  DependsOn(SigninManagerFactory::GetInstance());
+  DependsOn(IdentityManagerFactory::GetInstance());
 }
 
 SigninErrorControllerFactory::~SigninErrorControllerFactory() {}
@@ -48,6 +44,5 @@
           : SigninErrorController::AccountMode::PRIMARY_ACCOUNT;
 #endif
   return new SigninErrorController(
-      account_mode, ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
-      SigninManagerFactory::GetForProfile(profile));
+      account_mode, IdentityManagerFactory::GetForProfile(profile));
 }
diff --git a/chrome/browser/ssl/security_state_tab_helper_unittest.cc b/chrome/browser/ssl/security_state_tab_helper_unittest.cc
index 0bc60e3d..9f4ac96 100644
--- a/chrome/browser/ssl/security_state_tab_helper_unittest.cc
+++ b/chrome/browser/ssl/security_state_tab_helper_unittest.cc
@@ -11,7 +11,7 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/security_state/content/ssl_status_input_event_data.h"
 #include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/navigation_handle.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -57,10 +57,13 @@
   }
 
   void StartFormSubmissionNavigation() {
-    std::unique_ptr<content::NavigationHandle> handle =
-        content::NavigationHandle::CreateNavigationHandleForTesting(
-            GURL("http://example.test"), web_contents()->GetMainFrame(), true,
-            net::OK, false, false, ui::PAGE_TRANSITION_LINK, true);
+    content::MockNavigationHandle handle(GURL("http://example.test"),
+                                         web_contents()->GetMainFrame());
+    handle.set_is_form_submission(true);
+    helper_->DidStartNavigation(&handle);
+
+    handle.set_has_committed(true);
+    helper_->DidFinishNavigation(&handle);
   }
 
   void NavigateToHTTP() { NavigateAndCommit(GURL("http://example.test")); }
diff --git a/chrome/browser/ssl/ssl_error_navigation_throttle_unittest.cc b/chrome/browser/ssl/ssl_error_navigation_throttle_unittest.cc
index 11a8156..2b0e960 100644
--- a/chrome/browser/ssl/ssl_error_navigation_throttle_unittest.cc
+++ b/chrome/browser/ssl/ssl_error_navigation_throttle_unittest.cc
@@ -12,8 +12,8 @@
 #include "chrome/browser/ssl/ssl_blocking_page.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/navigation_throttle.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "net/cert/cert_status_flags.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
@@ -90,22 +90,18 @@
     scoped_feature_list_.InitAndEnableFeature(
         features::kSSLCommittedInterstitials);
 
+    handle_ = std::make_unique<content::MockNavigationHandle>(web_contents());
+    handle_->set_has_committed(true);
+    handle_->set_net_error_code(net::ERR_CERT_INVALID);
     async_ = GetParam();
-    handle_ = content::NavigationHandle::CreateNavigationHandleForTesting(
-        GURL(), main_rfh(), true /* committed */, net::ERR_CERT_INVALID);
-
-    std::unique_ptr<TestSSLErrorNavigationThrottle> throttle =
-        std::make_unique<TestSSLErrorNavigationThrottle>(
-            handle_.get(), async_,
-            base::BindOnce(
-                &SSLErrorNavigationThrottleTest::RecordDeferredResult,
-                base::Unretained(this)));
-    handle_->RegisterThrottleForTesting(std::move(throttle));
+    throttle_ = std::make_unique<TestSSLErrorNavigationThrottle>(
+        handle_.get(), async_,
+        base::BindOnce(&SSLErrorNavigationThrottleTest::RecordDeferredResult,
+                       base::Unretained(this)));
   }
 
   // content::RenderViewHostTestHarness:
   void TearDown() override {
-    handle_.reset();
     ChromeRenderViewHostTestHarness::TearDown();
   }
 
@@ -116,7 +112,8 @@
 
  protected:
   bool async_ = false;
-  std::unique_ptr<content::NavigationHandle> handle_;
+  std::unique_ptr<content::MockNavigationHandle> handle_;
+  std::unique_ptr<TestSSLErrorNavigationThrottle> throttle_;
   content::NavigationThrottle::ThrottleCheckResult deferred_result_ =
       content::NavigationThrottle::DEFER;
 
@@ -131,7 +128,7 @@
                << "Asynchronous MockHandleSSLError: " << async_);
 
   content::NavigationThrottle::ThrottleCheckResult result =
-      handle_->CallWillFailRequestForTesting(main_rfh(), base::nullopt);
+      throttle_->WillFailRequest();
 
   EXPECT_FALSE(handle_->GetSSLInfo().is_valid());
   EXPECT_EQ(content::NavigationThrottle::PROCEED, result);
@@ -145,8 +142,9 @@
 
   net::SSLInfo ssl_info;
   ssl_info.cert_status = net::CERT_STATUS_IS_EV;
+  handle_->set_ssl_info(ssl_info);
   content::NavigationThrottle::ThrottleCheckResult result =
-      handle_->CallWillFailRequestForTesting(main_rfh(), ssl_info);
+      throttle_->WillFailRequest();
 
   EXPECT_EQ(net::CERT_STATUS_IS_EV, handle_->GetSSLInfo().cert_status);
   EXPECT_EQ(content::NavigationThrottle::PROCEED, result);
@@ -162,8 +160,9 @@
   ssl_info.cert =
       net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
   ssl_info.cert_status = net::CERT_STATUS_COMMON_NAME_INVALID;
+  handle_->set_ssl_info(ssl_info);
   content::NavigationThrottle::ThrottleCheckResult synchronous_result =
-      handle_->CallWillFailRequestForTesting(main_rfh(), ssl_info);
+      throttle_->WillFailRequest();
 
   EXPECT_EQ(content::NavigationThrottle::DEFER, synchronous_result.action());
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/ssl/typed_navigation_timing_throttle_unittest.cc b/chrome/browser/ssl/typed_navigation_timing_throttle_unittest.cc
index b869658..046afe8 100644
--- a/chrome/browser/ssl/typed_navigation_timing_throttle_unittest.cc
+++ b/chrome/browser/ssl/typed_navigation_timing_throttle_unittest.cc
@@ -6,8 +6,8 @@
 
 #include "base/test/metrics/histogram_tester.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/navigation_throttle.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -17,26 +17,18 @@
 // Tests that the throttle is created for navigations to HTTP URLs.
 TEST_F(TypedNavigationTimingThrottleTest, IsCreatedForHTTP) {
   GURL http_url("http://example.test");
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(http_url,
-                                                                  main_rfh());
+  content::MockNavigationHandle handle(http_url, main_rfh());
   std::unique_ptr<content::NavigationThrottle> throttle =
-      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(handle.get());
+      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(&handle);
   EXPECT_TRUE(throttle);
 }
 
 // Tests that the throttle is not created if the URL is HTTPS.
 TEST_F(TypedNavigationTimingThrottleTest, NotCreatedForHTTPS) {
   GURL https_url("https://example.test");
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          https_url, main_rfh(), false, /* committed */
-          net::OK,                      /* error */
-          false,                        /* is_same_document */
-          false,                        /* is_post */
-          ui::PAGE_TRANSITION_TYPED);
+  content::MockNavigationHandle handle(https_url, main_rfh());
   std::unique_ptr<content::NavigationThrottle> throttle =
-      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(handle.get());
+      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(&handle);
   EXPECT_FALSE(throttle);
 }
 
@@ -45,25 +37,19 @@
   base::HistogramTester test;
 
   GURL http_url("http://example.test");
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          http_url, main_rfh(), false, /* committed */
-          net::OK,                     /* error */
-          false,                       /* is_same_document */
-          false,                       /* is_post */
-          ui::PAGE_TRANSITION_TYPED);
+  content::MockNavigationHandle handle(http_url, main_rfh());
+  handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
+  std::unique_ptr<content::NavigationThrottle> throttle =
+      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(&handle);
+  ASSERT_TRUE(throttle);
 
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle->CallWillStartRequestForTesting().action());
+            throttle->WillStartRequest().action());
 
   GURL https_url("https://example.test");
+  handle.set_url(https_url);
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle
-                ->CallWillRedirectRequestForTesting(
-                    https_url, false, /* new_method_is_post */
-                    http_url,         /* new_referrer_url */
-                    false /* new_is_external_protocol */)
-                .action());
+            throttle->WillRedirectRequest().action());
 
   test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 1);
 }
@@ -73,16 +59,14 @@
   base::HistogramTester test;
 
   GURL http_url("http://example.test");
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          http_url, main_rfh(), false, /* committed */
-          net::OK,                     /* error */
-          false,                       /* is_same_document */
-          false,                       /* is_post */
-          ui::PAGE_TRANSITION_TYPED);
+  content::MockNavigationHandle handle(http_url, main_rfh());
+  handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
+  std::unique_ptr<content::NavigationThrottle> throttle =
+      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(&handle);
+  ASSERT_TRUE(throttle);
 
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle->CallWillStartRequestForTesting().action());
+            throttle->WillStartRequest().action());
 
   test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 0);
 }
@@ -93,25 +77,20 @@
   base::HistogramTester test;
 
   GURL http_url("http://example.test");
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          http_url, main_rfh(), false, /* committed */
-          net::OK,                     /* error */
-          false,                       /* is_same_document */
-          false,                       /* is_post */
-          ui::PAGE_TRANSITION_TYPED);
+  content::MockNavigationHandle handle(http_url, main_rfh());
+  handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
+  std::unique_ptr<content::NavigationThrottle> throttle =
+      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(&handle);
+  ASSERT_TRUE(throttle);
 
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle->CallWillStartRequestForTesting().action());
+            throttle->WillStartRequest().action());
 
   GURL other_url("http://nonexample.test");
+  handle.set_url(other_url);
+
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle
-                ->CallWillRedirectRequestForTesting(
-                    other_url, false, /* new_method_is_post */
-                    http_url,         /* new_referrer_url */
-                    false /* new_is_external_protocol */)
-                .action());
+            throttle->WillStartRequest().action());
 
   test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 0);
 }
@@ -122,25 +101,20 @@
   base::HistogramTester test;
 
   GURL http_url("http://example.test");
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          http_url, main_rfh(), false, /* committed */
-          net::OK,                     /* error */
-          false,                       /* is_same_document */
-          false,                       /* is_post */
-          ui::PAGE_TRANSITION_TYPED);
+  content::MockNavigationHandle handle(http_url, main_rfh());
+  handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
+  std::unique_ptr<content::NavigationThrottle> throttle =
+      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(&handle);
+  ASSERT_TRUE(throttle);
 
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle->CallWillStartRequestForTesting().action());
+            throttle->WillStartRequest().action());
 
   GURL other_url("https://nonexample.test");
+  handle.set_url(other_url);
+
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle
-                ->CallWillRedirectRequestForTesting(
-                    other_url, false, /* new_method_is_post */
-                    http_url,         /* new_referrer_url */
-                    false /* new_is_external_protocol */)
-                .action());
+            throttle->WillStartRequest().action());
 
   test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 0);
 }
@@ -151,21 +125,18 @@
   base::HistogramTester test;
 
   GURL http_url("http://example.test");
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(http_url,
-                                                                  main_rfh());
+  content::MockNavigationHandle handle(http_url, main_rfh());
+  std::unique_ptr<content::NavigationThrottle> throttle =
+      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(&handle);
+  ASSERT_TRUE(throttle);
 
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle->CallWillStartRequestForTesting().action());
+            throttle->WillStartRequest().action());
 
   GURL https_url("https://example.test");
+  handle.set_url(https_url);
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle
-                ->CallWillRedirectRequestForTesting(
-                    https_url, false, /* new_method_is_post */
-                    http_url,         /* new_referrer_url */
-                    false /* new_is_external_protocol */)
-                .action());
+            throttle->WillRedirectRequest().action());
 
   test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 0);
 }
@@ -176,53 +147,34 @@
   base::HistogramTester test;
 
   GURL http_url("http://example.test");
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          http_url, main_rfh(), false, /* committed */
-          net::OK,                     /* error */
-          false,                       /* is_same_document */
-          false,                       /* is_post */
-          ui::PAGE_TRANSITION_TYPED);
+  content::MockNavigationHandle handle(http_url, main_rfh());
+  handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
+  std::unique_ptr<content::NavigationThrottle> throttle =
+      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(&handle);
+  ASSERT_TRUE(throttle);
 
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle->CallWillStartRequestForTesting().action());
+            throttle->WillStartRequest().action());
 
   // Redirecting to the "upgraded" URL twice in a row should result in only one
   // activation of the histogram trigger.
   GURL https_url("https://example.test");
+  handle.set_url(https_url);
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle
-                ->CallWillRedirectRequestForTesting(
-                    https_url, false, /* new_method_is_post */
-                    http_url,         /* new_referrer_url */
-                    false /* new_is_external_protocol */)
-                .action());
+            throttle->WillRedirectRequest().action());
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle
-                ->CallWillRedirectRequestForTesting(
-                    https_url, false, /* new_method_is_post */
-                    http_url,         /* new_referrer_url */
-                    false /* new_is_external_protocol */)
-                .action());
+            throttle->WillRedirectRequest().action());
 
   // Other redirects should also not affect the histogram.
   GURL other_http_url("http://nonexample.test");
+  handle.set_url(other_http_url);
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle
-                ->CallWillRedirectRequestForTesting(
-                    other_http_url, false, /* new_method_is_post */
-                    https_url,             /* new_referrer_url */
-                    false /* new_is_external_protocol */)
-                .action());
+            throttle->WillRedirectRequest().action());
 
   GURL other_https_url("https://nonexample.test");
+  handle.set_url(other_https_url);
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle
-                ->CallWillRedirectRequestForTesting(
-                    other_https_url, false, /* new_method_is_post */
-                    other_http_url,         /* new_referrer_url */
-                    false /* new_is_external_protocol */)
-                .action());
+            throttle->WillRedirectRequest().action());
 
   test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 1);
 }
@@ -232,25 +184,19 @@
   base::HistogramTester test;
 
   GURL http_url("http://example.test");
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          http_url, main_rfh(), false, /* committed */
-          net::OK,                     /* error */
-          false,                       /* is_same_document */
-          false,                       /* is_post */
-          ui::PAGE_TRANSITION_TYPED);
+  content::MockNavigationHandle handle(http_url, main_rfh());
+  handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
+  std::unique_ptr<content::NavigationThrottle> throttle =
+      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(&handle);
+  ASSERT_TRUE(throttle);
 
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle->CallWillStartRequestForTesting().action());
+            throttle->WillStartRequest().action());
 
   GURL https_url("https://www.example.test");
+  handle.set_url(https_url);
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle
-                ->CallWillRedirectRequestForTesting(
-                    https_url, false, /* new_method_is_post */
-                    http_url,         /* new_referrer_url */
-                    false /* new_is_external_protocol */)
-                .action());
+            throttle->WillRedirectRequest().action());
 
   test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 1);
 }
@@ -260,25 +206,19 @@
   base::HistogramTester test;
 
   GURL http_url("http://www.example.test");
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          http_url, main_rfh(), false, /* committed */
-          net::OK,                     /* error */
-          false,                       /* is_same_document */
-          false,                       /* is_post */
-          ui::PAGE_TRANSITION_TYPED);
+  content::MockNavigationHandle handle(http_url, main_rfh());
+  handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
+  std::unique_ptr<content::NavigationThrottle> throttle =
+      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(&handle);
+  ASSERT_TRUE(throttle);
 
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle->CallWillStartRequestForTesting().action());
+            throttle->WillStartRequest().action());
 
   GURL https_url("https://example.test");
+  handle.set_url(https_url);
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle
-                ->CallWillRedirectRequestForTesting(
-                    https_url, false, /* new_method_is_post */
-                    http_url,         /* new_referrer_url */
-                    false /* new_is_external_protocol */)
-                .action());
+            throttle->WillRedirectRequest().action());
 
   test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 1);
 }
@@ -288,25 +228,19 @@
   base::HistogramTester test;
 
   GURL http_url("http://example.test:8080");
-  std::unique_ptr<content::NavigationHandle> handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          http_url, main_rfh(), false, /* committed */
-          net::OK,                     /* error */
-          false,                       /* is_same_document */
-          false,                       /* is_post */
-          ui::PAGE_TRANSITION_TYPED);
+  content::MockNavigationHandle handle(http_url, main_rfh());
+  handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
+  std::unique_ptr<content::NavigationThrottle> throttle =
+      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(&handle);
+  ASSERT_TRUE(throttle);
 
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle->CallWillStartRequestForTesting().action());
+            throttle->WillStartRequest().action());
 
   GURL https_url("https://example.test:4443");
+  handle.set_url(https_url);
   EXPECT_EQ(content::NavigationThrottle::PROCEED,
-            handle
-                ->CallWillRedirectRequestForTesting(
-                    https_url, false, /* new_method_is_post */
-                    http_url,         /* new_referrer_url */
-                    false /* new_is_external_protocol */)
-                .action());
+            throttle->WillRedirectRequest().action());
 
   test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 1);
 }
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service.cc b/chrome/browser/supervised_user/child_accounts/child_account_service.cc
index 97fb7f8..fe1b53a 100644
--- a/chrome/browser/supervised_user/child_accounts/child_account_service.cc
+++ b/chrome/browser/supervised_user/child_accounts/child_account_service.cc
@@ -15,8 +15,8 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/gaia_cookie_manager_service_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.h"
 #include "chrome/browser/supervised_user/experimental/safe_search_url_reporter.h"
 #include "chrome/browser/supervised_user/supervised_user_constants.h"
@@ -32,10 +32,10 @@
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/browser/signin_pref_names.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
+#include "services/identity/public/cpp/identity_manager.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -112,12 +112,10 @@
 
   // If we're already signed in, check the account immediately just to be sure.
   // (We might have missed an update before registering as an observer.)
-  SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile_);
-  if (signin->IsAuthenticated()) {
-    OnAccountUpdated(
-        AccountTrackerServiceFactory::GetForProfile(profile_)->GetAccountInfo(
-            signin->GetAuthenticatedAccountId()));
-  }
+  identity::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfile(profile_);
+  if (identity_manager->HasPrimaryAccount())
+    OnAccountUpdated(identity_manager->GetPrimaryAccountInfo());
 }
 
 bool ChildAccountService::IsChildAccountStatusKnown() {
@@ -266,8 +264,8 @@
     return;
   }
 
-  std::string auth_account_id = SigninManagerFactory::GetForProfile(profile_)
-      ->GetAuthenticatedAccountId();
+  std::string auth_account_id =
+      IdentityManagerFactory::GetForProfile(profile_)->GetPrimaryAccountId();
   if (info.account_id != auth_account_id)
     return;
 
@@ -323,8 +321,7 @@
 void ChildAccountService::StartFetchingFamilyInfo() {
   family_fetcher_.reset(new FamilyInfoFetcher(
       this,
-      SigninManagerFactory::GetForProfile(profile_)
-          ->GetAuthenticatedAccountId(),
+      IdentityManagerFactory::GetForProfile(profile_)->GetPrimaryAccountId(),
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile_),
       content::BrowserContext::GetDefaultStoragePartition(profile_)
           ->GetURLLoaderFactoryForBrowserProcess()));
diff --git a/chrome/browser/sync/sessions/sync_sessions_router_tab_helper_unittest.cc b/chrome/browser/sync/sessions/sync_sessions_router_tab_helper_unittest.cc
index ae34ba0..a1af0bdd 100644
--- a/chrome/browser/sync/sessions/sync_sessions_router_tab_helper_unittest.cc
+++ b/chrome/browser/sync/sessions/sync_sessions_router_tab_helper_unittest.cc
@@ -12,7 +12,7 @@
 #include "chrome/browser/ui/sync/browser_synced_tab_delegate.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
-#include "content/public/browser/navigation_handle.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/web_contents_tester.h"
@@ -78,10 +78,8 @@
       content::RenderFrameHostTester::For(main_rfh())->AppendChild("subframe");
   GURL child_url("http://foobar.com");
 
-  std::unique_ptr<content::NavigationHandle> test_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(child_url,
-                                                                  child_rfh);
-  helper->DidFinishNavigation(test_handle.get());
+  content::MockNavigationHandle test_handle(child_url, child_rfh);
+  helper->DidFinishNavigation(&test_handle);
   EXPECT_FALSE(handler()->was_notified_since_last_call());
 
   helper->DidFinishLoad(child_rfh, GURL());
diff --git a/chrome/browser/sync/test/integration/autofill_helper.cc b/chrome/browser/sync/test/integration/autofill_helper.cc
index 8629fbb..3da2bb0 100644
--- a/chrome/browser/sync/test/integration/autofill_helper.cc
+++ b/chrome/browser/sync/test/integration/autofill_helper.cc
@@ -160,6 +160,10 @@
 
 namespace autofill_helper {
 
+ACTION_P(QuitMessageLoop, loop) {
+  loop->Quit();
+}
+
 AutofillProfile CreateAutofillProfile(ProfileType type) {
   AutofillProfile profile;
   switch (type) {
@@ -269,7 +273,20 @@
 }
 
 void SetProfiles(int profile, std::vector<AutofillProfile>* autofill_profiles) {
-  GetPersonalDataManager(profile)->SetProfiles(autofill_profiles);
+  PersonalDataLoadedObserverMock personal_data_observer;
+  PersonalDataManager* pdm = GetPersonalDataManager(profile);
+  base::RunLoop run_loop;
+
+  pdm->AddObserver(&personal_data_observer);
+  EXPECT_CALL(personal_data_observer, OnPersonalDataFinishedProfileTasks())
+      .WillOnce(QuitMessageLoop(&run_loop));
+  EXPECT_CALL(personal_data_observer, OnPersonalDataChanged())
+      .Times(testing::AnyNumber());
+
+  pdm->SetProfiles(autofill_profiles);
+
+  run_loop.Run();
+  pdm->RemoveObserver(&personal_data_observer);
 }
 
 void SetCreditCards(int profile, std::vector<CreditCard>* credit_cards) {
@@ -310,8 +327,16 @@
 }
 
 std::vector<AutofillProfile*> GetAllAutoFillProfiles(int profile) {
+  PersonalDataLoadedObserverMock personal_data_observer;
+  base::RunLoop run_loop;
+
   PersonalDataManager* pdm = GetPersonalDataManager(profile);
+  pdm->AddObserver(&personal_data_observer);
+
   pdm->Refresh();
+  EXPECT_CALL(personal_data_observer, OnPersonalDataFinishedProfileTasks())
+      .WillOnce(QuitMessageLoop(&run_loop));
+  EXPECT_CALL(personal_data_observer, OnPersonalDataChanged()).Times(1);
 
   // PersonalDataManager::GetProfiles() simply returns the current values that
   // have been last reported to the UI sequence. PersonalDataManager::Refresh()
@@ -328,6 +353,8 @@
   // cancel outstanding queries, this is only instigated on the UI sequence,
   // which we are about to block, which means we are safe.
   WaitForCurrentTasksToComplete(GetWebDataService(profile)->GetDBTaskRunner());
+  run_loop.Run();
+  pdm->RemoveObserver(&personal_data_observer);
 
   return pdm->GetProfiles();
 }
@@ -377,15 +404,37 @@
 }
 
 bool AutofillProfileChecker::Wait() {
-  autofill_helper::GetPersonalDataManager(profile_a_)->Refresh();
-  autofill_helper::GetPersonalDataManager(profile_b_)->Refresh();
+  PersonalDataLoadedObserverMock personal_data_observer;
+  base::RunLoop run_loop_a;
+  base::RunLoop run_loop_b;
+  auto* pdm_a = autofill_helper::GetPersonalDataManager(profile_a_);
+  auto* pdm_b = autofill_helper::GetPersonalDataManager(profile_b_);
+  pdm_a->AddObserver(&personal_data_observer);
+  pdm_b->AddObserver(&personal_data_observer);
+
+  EXPECT_CALL(personal_data_observer, OnPersonalDataChanged())
+      .Times(testing::AnyNumber());
+
+  EXPECT_CALL(personal_data_observer, OnPersonalDataFinishedProfileTasks())
+      .WillRepeatedly(autofill_helper::QuitMessageLoop(&run_loop_a));
+  pdm_a->Refresh();
   // Similar to GetAllAutoFillProfiles() we need to make sure we are not reading
   // before any locally instigated async writes. This is run exactly one time
   // before the first IsExitConditionSatisfied() is called.
   WaitForCurrentTasksToComplete(
       GetWebDataService(profile_a_)->GetDBTaskRunner());
+  run_loop_a.Run();
+
+  EXPECT_CALL(personal_data_observer, OnPersonalDataFinishedProfileTasks())
+      .WillRepeatedly(autofill_helper::QuitMessageLoop(&run_loop_b));
+  pdm_b->Refresh();
   WaitForCurrentTasksToComplete(
       GetWebDataService(profile_b_)->GetDBTaskRunner());
+  run_loop_b.Run();
+
+  pdm_a->RemoveObserver(&personal_data_observer);
+  pdm_b->RemoveObserver(&personal_data_observer);
+
   return StatusChangeChecker::Wait();
 }
 
@@ -405,3 +454,6 @@
 void AutofillProfileChecker::OnPersonalDataChanged() {
   CheckExitCondition();
 }
+
+PersonalDataLoadedObserverMock::PersonalDataLoadedObserverMock() {}
+PersonalDataLoadedObserverMock::~PersonalDataLoadedObserverMock() {}
diff --git a/chrome/browser/sync/test/integration/autofill_helper.h b/chrome/browser/sync/test/integration/autofill_helper.h
index 00c99bd6..e9f1070 100644
--- a/chrome/browser/sync/test/integration/autofill_helper.h
+++ b/chrome/browser/sync/test/integration/autofill_helper.h
@@ -14,6 +14,7 @@
 #include "base/strings/string16.h"
 #include "chrome/browser/sync/test/integration/multi_client_status_change_checker.h"
 #include "components/autofill/core/browser/personal_data_manager_observer.h"
+#include "testing/gmock/include/gmock/gmock.h"
 
 namespace autofill {
 class AutofillEntry;
@@ -137,4 +138,14 @@
   const int profile_b_;
 };
 
+class PersonalDataLoadedObserverMock
+    : public autofill::PersonalDataManagerObserver {
+ public:
+  PersonalDataLoadedObserverMock();
+  ~PersonalDataLoadedObserverMock() override;
+
+  MOCK_METHOD0(OnPersonalDataChanged, void());
+  MOCK_METHOD0(OnPersonalDataFinishedProfileTasks, void());
+};
+
 #endif  // CHROME_BROWSER_SYNC_TEST_INTEGRATION_AUTOFILL_HELPER_H_
diff --git a/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc b/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
index f809691..e4f750d1 100644
--- a/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
@@ -225,16 +225,13 @@
 
   // Add the same (but non-verified) profile on the other client, afterwards.
   AddProfile(0, profile0);
-  // This call avoids the standard de-duping mechanisms in PDM so there will be
-  // two profiles at client 0 for a while. In this sense, this test is not very
-  // realistic as this should not happen in reality. The test checks that
-  // autofill_profile sync is robust enough to handle this situation.
-  EXPECT_EQ(2U, GetAllAutoFillProfiles(0).size());
   EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
 
-  // The profiles should de-duplicate via sync on the other client, the verified
-  // one should win.
+  // The profiles should de-duplicate via sync on both other client, the
+  // verified one should win.
   EXPECT_EQ(1U, GetAllAutoFillProfiles(0).size());
+  EXPECT_EQ(1U, GetAllAutoFillProfiles(0).size());
+
   EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(0)[0]->origin());
   EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(1)[0]->origin());
 }
diff --git a/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc
index 4b35479..cde6e4d 100644
--- a/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc
@@ -564,9 +564,8 @@
   EXPECT_EQ(kLocalBillingAddressId, credit_cards[0]->billing_address_id());
 }
 
-// Disabled due to flakiness: https://crbug.com/917498.
 IN_PROC_BROWSER_TEST_P(TwoClientWalletSyncTest,
-                       DISABLED_ServerAddressConvertsToSameLocalAddress) {
+                       ServerAddressConvertsToSameLocalAddress) {
   InitWithDefaultFeatures();
 
   GetFakeServer()->SetWalletData(
@@ -584,13 +583,13 @@
   EXPECT_TRUE(server_addresses[0]->has_converted());
 
   // Make sure they have the same local profile.
-  std::vector<AutofillProfile*> local_addresses = GetLocalProfiles(0);
-  EXPECT_EQ(1u, local_addresses.size());
-  const std::string& guid = local_addresses[0]->guid();
+  std::vector<AutofillProfile*> local_addresses_0 = GetLocalProfiles(0);
+  EXPECT_EQ(1u, local_addresses_0.size());
 
-  local_addresses = GetLocalProfiles(1);
-  EXPECT_EQ(1u, local_addresses.size());
-  EXPECT_EQ(guid, local_addresses[0]->guid());
+  std::vector<AutofillProfile*> local_addresses_1 = GetLocalProfiles(1);
+  EXPECT_EQ(1u, local_addresses_1.size());
+  EXPECT_TRUE(
+      local_addresses_0[0]->EqualsForSyncPurposes(*local_addresses_1[0]));
 }
 
 IN_PROC_BROWSER_TEST_P(TwoClientWalletSyncTest,
diff --git a/chrome/browser/ui/autofill/local_card_migration_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/local_card_migration_bubble_controller_impl_unittest.cc
index 9cf49a7e..e7fa08b 100644
--- a/chrome/browser/ui/autofill/local_card_migration_bubble_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/local_card_migration_bubble_controller_impl_unittest.cc
@@ -17,7 +17,7 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/autofill/core/browser/autofill_metrics.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
-#include "content/public/browser/navigation_handle.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -46,10 +46,9 @@
 
   void SimulateNavigation() {
     content::RenderFrameHost* rfh = web_contents()->GetMainFrame();
-    std::unique_ptr<content::NavigationHandle> navigation_handle =
-        content::NavigationHandle::CreateNavigationHandleForTesting(GURL(), rfh,
-                                                                    true);
-    // Destructor calls DidFinishNavigation.
+    content::MockNavigationHandle navigation_handle(GURL(), rfh);
+    navigation_handle.set_has_committed(true);
+    DidFinishNavigation(&navigation_handle);
   }
 
  protected:
@@ -296,4 +295,4 @@
           Bucket(AutofillMetrics::LOCAL_CARD_MIGRATION_BUBBLE_SHOWN, 1)));
 }
 
-}  // namespace autofill
\ No newline at end of file
+}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc
index 8d4b4ef..437b467 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc
@@ -27,7 +27,7 @@
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/autofill_prefs.h"
 #include "components/user_prefs/user_prefs.h"
-#include "content/public/browser/navigation_handle.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -56,11 +56,9 @@
   }
 
   void SimulateNavigation() {
-    content::RenderFrameHost* rfh = web_contents()->GetMainFrame();
-    std::unique_ptr<content::NavigationHandle> navigation_handle =
-        content::NavigationHandle::CreateNavigationHandleForTesting(
-            GURL(), rfh, true);
-    // Destructor calls DidFinishNavigation.
+    content::MockNavigationHandle handle;
+    handle.set_has_committed(true);
+    DidFinishNavigation(&handle);
   }
 
  protected:
diff --git a/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper_unittest.cc b/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper_unittest.cc
index 817978f..ae84766 100644
--- a/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper_unittest.cc
+++ b/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper_unittest.cc
@@ -5,8 +5,8 @@
 #include "chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/common/page_importance_signals.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/web_contents_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -26,36 +26,30 @@
 TEST_F(BloatedRendererTabHelperTest, DetectReload) {
   EXPECT_EQ(BloatedRendererTabHelper::State::kInactive, tab_helper_->state_);
   tab_helper_->state_ = BloatedRendererTabHelper::State::kRequestingReload;
-  auto reload_navigation =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(), web_contents()->GetMainFrame());
-  tab_helper_->DidStartNavigation(reload_navigation.get());
+  content::MockNavigationHandle reload_navigation;
+  tab_helper_->DidStartNavigation(&reload_navigation);
   EXPECT_EQ(BloatedRendererTabHelper::State::kStartedNavigation,
             tab_helper_->state_);
-  EXPECT_EQ(reload_navigation->GetNavigationId(),
+  EXPECT_EQ(reload_navigation.GetNavigationId(),
             tab_helper_->saved_navigation_id_);
-  tab_helper_->DidFinishNavigation(reload_navigation.get());
+  tab_helper_->DidFinishNavigation(&reload_navigation);
   EXPECT_EQ(BloatedRendererTabHelper::State::kInactive, tab_helper_->state_);
 }
 
 TEST_F(BloatedRendererTabHelperTest, IgnoreUnrelatedNavigation) {
   EXPECT_EQ(BloatedRendererTabHelper::State::kInactive, tab_helper_->state_);
   tab_helper_->state_ = BloatedRendererTabHelper::State::kRequestingReload;
-  auto reload_navigation =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(), web_contents()->GetMainFrame());
-  tab_helper_->DidStartNavigation(reload_navigation.get());
+  content::MockNavigationHandle reload_navigation;
+  tab_helper_->DidStartNavigation(&reload_navigation);
   EXPECT_EQ(BloatedRendererTabHelper::State::kStartedNavigation,
             tab_helper_->state_);
-  EXPECT_EQ(reload_navigation->GetNavigationId(),
+  EXPECT_EQ(reload_navigation.GetNavigationId(),
             tab_helper_->saved_navigation_id_);
-  auto unrelated_navigation =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(), web_contents()->GetMainFrame());
-  tab_helper_->DidFinishNavigation(unrelated_navigation.get());
+  content::MockNavigationHandle unrelated_navigation;
+  tab_helper_->DidFinishNavigation(&unrelated_navigation);
   EXPECT_EQ(BloatedRendererTabHelper::State::kStartedNavigation,
             tab_helper_->state_);
-  EXPECT_EQ(reload_navigation->GetNavigationId(),
+  EXPECT_EQ(reload_navigation.GetNavigationId(),
             tab_helper_->saved_navigation_id_);
 }
 
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
index 0a74950..0d8d67b3 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
@@ -37,6 +37,7 @@
 #include "components/ukm/test_ukm_recorder.h"
 #include "components/variations/variations_associated_data.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
 #include "content/public/test/web_contents_tester.h"
@@ -494,10 +495,9 @@
     EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility());
     controller()->OnBubbleHidden();
     EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility());
-    std::unique_ptr<content::NavigationHandle> navigation_handle =
-        content::NavigationHandle::CreateNavigationHandleForTesting(
-            GURL(), main_rfh(), true);
-    navigation_handle.reset();  // Calls DidFinishNavigation.
+    content::MockNavigationHandle test_handle(web_contents());
+    test_handle.set_has_committed(true);
+    controller()->DidFinishNavigation(&test_handle);
 
     recorder = nullptr;
     ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(controller()));
@@ -569,10 +569,9 @@
   // Fake-navigate. We expect the bubble's state to persist so a user reasonably
   // has been able to interact with the bubble. This happens on
   // `accounts.google.com`, for instance.
-  std::unique_ptr<content::NavigationHandle> navigation_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(), main_rfh(), true);
-  navigation_handle.reset();  // Calls DidFinishNavigation.
+  content::MockNavigationHandle test_handle(web_contents());
+  test_handle.set_has_committed(true);
+  controller()->DidFinishNavigation(&test_handle);
   ExpectIconAndControllerStateIs(password_manager::ui::PENDING_PASSWORD_STATE);
 }
 
@@ -590,10 +589,9 @@
 
   // Fake-navigate. There is no bubble, reset the state.
   EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility());
-  std::unique_ptr<content::NavigationHandle> navigation_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(), main_rfh(), true);
-  navigation_handle.reset();  // Calls DidFinishNavigation.
+  content::MockNavigationHandle test_handle(web_contents());
+  test_handle.set_has_committed(true);
+  controller()->DidFinishNavigation(&test_handle);
   ExpectIconAndControllerStateIs(password_manager::ui::INACTIVE_STATE);
 }
 
@@ -843,10 +841,9 @@
   // The dialog should survive any navigation.
   EXPECT_CALL(dialog_prompt(), ControllerGone()).Times(0);
   EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility());
-  std::unique_ptr<content::NavigationHandle> navigation_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(), main_rfh(), true);
-  navigation_handle.reset();  // Calls DidFinishNavigation.
+  content::MockNavigationHandle test_handle(web_contents());
+  test_handle.set_has_committed(true);
+  controller()->DidFinishNavigation(&test_handle);
   ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&dialog_prompt()));
   EXPECT_CALL(dialog_prompt(), ControllerGone());
 }
@@ -976,10 +973,9 @@
     // state is retained on navigation, and the PasswordFormManager is not
     // destroyed.
     controller()->OnBubbleHidden();
-    std::unique_ptr<content::NavigationHandle> navigation_handle =
-        content::NavigationHandle::CreateNavigationHandleForTesting(
-            GURL(), main_rfh(), true);
-    navigation_handle.reset();  // Calls DidFinishNavigation.
+    content::MockNavigationHandle test_handle(web_contents());
+    test_handle.set_has_committed(true);
+    controller()->DidFinishNavigation(&test_handle);
 
     recorder = nullptr;
     EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(controller()));
@@ -1078,10 +1074,9 @@
     testing::Mock::VerifyAndClearExpectations(controller());
     if (enforce_navigation) {
       // Fake-navigate. The fallback should persist.
-      std::unique_ptr<content::NavigationHandle> navigation_handle =
-          content::NavigationHandle::CreateNavigationHandleForTesting(
-              GURL(), main_rfh(), true);
-      navigation_handle.reset();  // Calls DidFinishNavigation.
+      content::MockNavigationHandle test_handle(web_contents());
+      test_handle.set_has_committed(true);
+      controller()->DidFinishNavigation(&test_handle);
       ExpectIconAndControllerStateIs(
           password_manager::ui::PENDING_PASSWORD_STATE);
     }
@@ -1134,10 +1129,9 @@
       // navigation.
       controller()->OnBubbleHidden();
       EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility());
-      std::unique_ptr<content::NavigationHandle> navigation_handle =
-          content::NavigationHandle::CreateNavigationHandleForTesting(
-              GURL(), main_rfh(), true);
-      navigation_handle.reset();  // Calls DidFinishNavigation.
+      content::MockNavigationHandle test_handle(web_contents());
+      test_handle.set_has_committed(true);
+      controller()->DidFinishNavigation(&test_handle);
       ExpectIconAndControllerStateIs(password_manager::ui::INACTIVE_STATE);
     }
     testing::Mock::VerifyAndClearExpectations(controller());
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
index 3149117..9b27c83 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -18,8 +18,7 @@
 #include "chrome/browser/profiles/profile_io_data.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_window.h"
-#include "chrome/browser/signin/account_tracker_service_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_tracker_factory.h"
 #include "chrome/browser/signin/signin_util.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
@@ -37,7 +36,6 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/account_id/account_id.h"
 #include "components/prefs/pref_service.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/browser/signin_metrics.h"
 #include "components/sync/base/sync_prefs.h"
 #include "components/sync/driver/sync_service.h"
@@ -46,6 +44,8 @@
 #include "components/unified_consent/unified_consent_service.h"
 #include "content/public/browser/storage_partition.h"
 #include "net/base/url_util.h"
+#include "services/identity/public/cpp/identity_manager.h"
+#include "services/identity/public/cpp/primary_account_mutator.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace {
@@ -97,7 +97,9 @@
   BrowserList::AddObserver(this);
   Initialize(profile, browser);
   DCHECK(!refresh_token.empty());
-  SigninManagerFactory::GetForProfile(profile_)->StartSignInWithRefreshToken(
+
+  DCHECK(primary_account_mutator_);
+  primary_account_mutator_->LegacyStartSigninWithRefreshTokenForPrimaryAccount(
       refresh_token, gaia_id, email, password,
       base::BindOnce(&OneClickSigninSyncStarter::ConfirmSignin,
                      weak_pointer_factory_.GetWeakPtr(), profile_mode));
@@ -132,20 +134,27 @@
   if (sync_service)
     sync_blocker_ = sync_service->GetSetupInProgressHandle();
 
-  // Make sure the syncing is requested, otherwise the SigninManager
-  // will not be able to complete successfully.
+  // Make sure the syncing is requested, otherwise the IdentityManager's primary
+  // account mutator will not be able to complete successfully.
   syncer::SyncPrefs sync_prefs(profile_->GetPrefs());
   sync_prefs.SetSyncRequested(true);
+
+  // Cache the IdentityManager's PrimaryAccountMutator each time the profile
+  // gets changed, as it will be used from multiple places in several methods.
+  primary_account_mutator_ = IdentityManagerFactory::GetForProfile(profile_)
+                                 ->GetPrimaryAccountMutator();
 }
 
 void OneClickSigninSyncStarter::ConfirmSignin(ProfileMode profile_mode,
                                               const std::string& oauth_token) {
-  SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
-  if (signin->IsAuthenticated()) {
-    // The user is already signed in - just tell SigninManager to continue
-    // with its re-auth flow.
+  identity::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfile(profile_);
+
+  if (identity_manager->HasPrimaryAccount()) {
+    // The user is already signed in - just tell IdentityManager's primary
+    // account mutator to continue with its re-auth flow.
     DCHECK_EQ(CURRENT_PROFILE, profile_mode);
-    signin->CompletePendingSignin();
+    primary_account_mutator_->LegacyCompletePendingPrimaryAccountSignin();
     return;
   }
 
@@ -157,7 +166,9 @@
       policy::UserPolicySigninService* policy_service =
           policy::UserPolicySigninServiceFactory::GetForProfile(profile_);
       policy_service->RegisterForPolicyWithLoginToken(
-          signin->GetUsernameForAuthInProgress(), oauth_token,
+          primary_account_mutator_->LegacyPrimaryAccountForAuthInProgress()
+              .email,
+          oauth_token,
           base::Bind(&OneClickSigninSyncStarter::OnRegisteredForPolicy,
                      weak_pointer_factory_.GetWeakPtr()));
       break;
@@ -209,7 +220,6 @@
 
 void OneClickSigninSyncStarter::OnRegisteredForPolicy(
     const std::string& dm_token, const std::string& client_id) {
-  SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
   // If there's no token for the user (policy registration did not succeed) just
   // finish signing in.
   if (dm_token.empty()) {
@@ -242,21 +252,26 @@
 
   base::RecordAction(
       base::UserMetricsAction("Signin_Show_EnterpriseAccountPrompt"));
+
   TabDialogs::FromWebContents(web_contents)
-      ->ShowProfileSigninConfirmation(browser_, profile_,
-                                      signin->GetUsernameForAuthInProgress(),
-                                      std::make_unique<SigninDialogDelegate>(
-                                          weak_pointer_factory_.GetWeakPtr()));
+      ->ShowProfileSigninConfirmation(
+          browser_, profile_,
+          primary_account_mutator_->LegacyPrimaryAccountForAuthInProgress()
+              .email,
+          std::make_unique<SigninDialogDelegate>(
+              weak_pointer_factory_.GetWeakPtr()));
 }
 
 void OneClickSigninSyncStarter::LoadPolicyWithCachedCredentials() {
   DCHECK(!dm_token_.empty());
   DCHECK(!client_id_.empty());
-  SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
   policy::UserPolicySigninService* policy_service =
       policy::UserPolicySigninServiceFactory::GetForProfile(profile_);
-  std::string username = signin->GetUsernameForAuthInProgress();
-  std::string gaia_id = signin->GetGaiaIdForAuthInProgress();
+
+  std::string username =
+      primary_account_mutator_->LegacyPrimaryAccountForAuthInProgress().email;
+  std::string gaia_id =
+      primary_account_mutator_->LegacyPrimaryAccountForAuthInProgress().gaia;
   DCHECK(username.empty() == gaia_id.empty());
   AccountId account_id =
       username.empty() ? EmptyAccountId()
@@ -272,23 +287,24 @@
 void OneClickSigninSyncStarter::OnPolicyFetchComplete(bool success) {
   // For now, we allow signin to complete even if the policy fetch fails. If
   // we ever want to change this behavior, we could call
-  // SigninManager::SignOut() here instead.
+  // PrimaryAccountMutator::ClearPrimaryAccount() here instead.
   DLOG_IF(ERROR, !success) << "Error fetching policy for user";
   DVLOG_IF(1, success) << "Policy fetch successful - completing signin";
-  SigninManagerFactory::GetForProfile(profile_)->CompletePendingSignin();
+
+  primary_account_mutator_->LegacyCompletePendingPrimaryAccountSignin();
 }
 
 void OneClickSigninSyncStarter::CreateNewSignedInProfile() {
-  SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
-  DCHECK(!signin->GetUsernameForAuthInProgress().empty());
+  const std::string email =
+      primary_account_mutator_->LegacyPrimaryAccountForAuthInProgress().email;
+  DCHECK(!email.empty());
 
   // Create a new profile and have it call back when done so we can inject our
   // signin credentials.
   size_t icon_index = g_browser_process->profile_manager()->
       GetProfileAttributesStorage().ChooseAvatarIconIndexForNewProfile();
   ProfileManager::CreateMultiProfileAsync(
-      base::UTF8ToUTF16(signin->GetUsernameForAuthInProgress()),
-      profiles::GetDefaultAvatarIconUrl(icon_index),
+      base::UTF8ToUTF16(email), profiles::GetDefaultAvatarIconUrl(icon_index),
       base::Bind(&OneClickSigninSyncStarter::CompleteInitForNewProfile,
                  weak_pointer_factory_.GetWeakPtr()));
 }
@@ -327,17 +343,24 @@
 void OneClickSigninSyncStarter::CopyCredentialsToNewProfileAndFinishSignin(
     Profile* new_profile) {
   // Wait until the profile is initialized before we transfer credentials.
-  SigninManager* old_signin_manager =
-      SigninManagerFactory::GetForProfile(profile_);
-  SigninManager* new_signin_manager =
-      SigninManagerFactory::GetForProfile(new_profile);
-  DCHECK(!old_signin_manager->GetUsernameForAuthInProgress().empty());
-  DCHECK(!old_signin_manager->IsAuthenticated());
-  DCHECK(!new_signin_manager->IsAuthenticated());
+  identity::IdentityManager* new_identity_manager =
+      IdentityManagerFactory::GetForProfile(new_profile);
+  auto* new_primary_account_mutator =
+      new_identity_manager->GetPrimaryAccountMutator();
+  DCHECK(new_primary_account_mutator);
+
+  DCHECK(!primary_account_mutator_->LegacyPrimaryAccountForAuthInProgress()
+              .email.empty());
+
+  identity::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfile(profile_);
+  DCHECK(!identity_manager->HasPrimaryAccount());
+  DCHECK(!new_identity_manager->HasPrimaryAccount());
 
   // Copy credentials from the old profile to the just-created profile,
   // and switch over to tracking that profile.
-  new_signin_manager->CopyCredentialsFrom(*old_signin_manager);
+  new_primary_account_mutator->LegacyCopyCredentialsFrom(
+      *primary_account_mutator_);
   FinishSyncServiceSetup();
   Initialize(new_profile, nullptr);
   DCHECK_EQ(profile_, new_profile);
@@ -346,9 +369,10 @@
   // the signin for the original profile was cancelled (must do this after
   // we have called Initialize() with the new profile, as otherwise this
   // object will get freed when the signin on the old profile is cancelled.
-  // SignoutAndRemoveAllAccounts does not actually remove the accounts. See
-  // http://crbug.com/799437.
-  old_signin_manager->SignOutAndRemoveAllAccounts(
+  // ClearPrimaryAccount does not actually remove the accounts if the
+  // signin is still pending. See http://crbug.com/799437.
+  primary_account_mutator_->ClearPrimaryAccount(
+      identity::PrimaryAccountMutator::ClearAccountsAction::kRemoveAll,
       signin_metrics::TRANSFER_CREDENTIALS,
       signin_metrics::SignoutDelete::IGNORE_METRIC);
 
@@ -359,7 +383,7 @@
     LoadPolicyWithCachedCredentials();
   } else {
     // No policy to load - simply complete the signin process.
-    SigninManagerFactory::GetForProfile(profile_)->CompletePendingSignin();
+    primary_account_mutator_->LegacyCompletePendingPrimaryAccountSignin();
   }
 
   // Unlock the new profile.
@@ -378,11 +402,12 @@
 }
 
 void OneClickSigninSyncStarter::CancelSigninAndDelete() {
-  SigninManager* signin_manager = SigninManagerFactory::GetForProfile(profile_);
-  DCHECK(signin_manager->AuthInProgress());
-  // SignoutAndRemoveAllAccounts does not actually remove the accounts if the
+  DCHECK(primary_account_mutator_->LegacyIsPrimaryAccountAuthInProgress());
+
+  // ClearPrimaryAccount does not actually remove the accounts if the
   // signin is still pending. See http://crbug.com/799437.
-  signin_manager->SignOutAndRemoveAllAccounts(
+  primary_account_mutator_->ClearPrimaryAccount(
+      identity::PrimaryAccountMutator::ClearAccountsAction::kRemoveAll,
       signin_metrics::ABORT_SIGNIN,
       signin_metrics::SignoutDelete::IGNORE_METRIC);
   // The statement above results in a call to SigninFailed() which will free
@@ -391,19 +416,20 @@
 }
 
 void OneClickSigninSyncStarter::ConfirmAndSignin() {
-  SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
   if (confirmation_required_ == CONFIRM_UNTRUSTED_SIGNIN) {
     browser_ = EnsureBrowser(browser_, profile_);
     base::RecordAction(
         base::UserMetricsAction("Signin_Show_UntrustedSigninPrompt"));
     // Display a confirmation dialog to the user.
     browser_->window()->ShowOneClickSigninConfirmation(
-        base::UTF8ToUTF16(signin->GetUsernameForAuthInProgress()),
+        base::UTF8ToUTF16(
+            primary_account_mutator_->LegacyPrimaryAccountForAuthInProgress()
+                .email),
         base::Bind(&OneClickSigninSyncStarter::UntrustedSigninConfirmed,
                    weak_pointer_factory_.GetWeakPtr()));
   } else {
     // No confirmation required - just sign in the user.
-    signin->CompletePendingSignin();
+    primary_account_mutator_->LegacyCompletePendingPrimaryAccountSignin();
   }
 }
 
@@ -413,8 +439,7 @@
     base::RecordAction(base::UserMetricsAction("Signin_Undo_Signin"));
     CancelSigninAndDelete();  // This statement frees this object.
   } else {
-    SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
-    signin->CompletePendingSignin();
+    primary_account_mutator_->LegacyCompletePendingPrimaryAccountSignin();
   }
 }
 
@@ -443,7 +468,8 @@
       break;
     }
     case LoginUIService::ABORT_SIGNIN:
-      SigninManagerFactory::GetForProfile(profile_)->SignOut(
+      primary_account_mutator_->ClearPrimaryAccount(
+          identity::PrimaryAccountMutator::ClearAccountsAction::kDefault,
           signin_metrics::ABORT_SIGNIN,
           signin_metrics::SignoutDelete::IGNORE_METRIC);
       FinishSyncServiceSetup();
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.h b/chrome/browser/ui/sync/one_click_signin_sync_starter.h
index 3d3144ca..20f393c7 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.h
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.h
@@ -20,6 +20,10 @@
 
 class Browser;
 
+namespace identity {
+class PrimaryAccountMutator;
+}
+
 namespace syncer {
 class SyncService;
 class SyncSetupInProgressHandle;
@@ -210,6 +214,7 @@
   Browser* browser_;
   signin_metrics::AccessPoint signin_access_point_;
   signin_metrics::Reason signin_reason_;
+  identity::PrimaryAccountMutator* primary_account_mutator_;
   std::unique_ptr<SigninTracker> signin_tracker_;
   ConfirmationRequired confirmation_required_;
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
index 5a3814c..e0acc523 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
@@ -171,7 +171,8 @@
       browser()->tab_strip_model()->GetActiveWebContents()->IsLoading());
 }
 
-IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, SelectAllOnClick) {
+// Flaky: https://crbug.com/915591.
+IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, DISABLED_SelectAllOnClick) {
   OmniboxView* omnibox_view = NULL;
   ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view));
   omnibox_view->SetUserText(base::ASCIIToUTF16("http://www.google.com/"));
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index 8de0071ea..2a165c8 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -385,6 +385,12 @@
      IDR_PDF_VIEWER_PDF_TOOLBAR_HTML},
     {"pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js",
      IDR_PDF_VIEWER_PDF_TOOLBAR_JS},
+#if defined(OS_CHROMEOS)
+    {"pdf/elements/viewer-pen-options/viewer-pen-options.html",
+     IDR_PDF_VIEWER_PEN_OPTIONS_HTML},
+    {"pdf/elements/viewer-pen-options/viewer-pen-options.js",
+     IDR_PDF_VIEWER_PEN_OPTIONS_JS},
+#endif
     {"pdf/elements/viewer-toolbar-dropdown/viewer-toolbar-dropdown.html",
      IDR_PDF_VIEWER_TOOLBAR_DROPDOWN_HTML},
     {"pdf/elements/viewer-toolbar-dropdown/viewer-toolbar-dropdown.js",
diff --git a/chrome/browser/ui/zoom/zoom_controller_unittest.cc b/chrome/browser/ui/zoom/zoom_controller_unittest.cc
index 2b7bc51b..49d1943 100644
--- a/chrome/browser/ui/zoom/zoom_controller_unittest.cc
+++ b/chrome/browser/ui/zoom/zoom_controller_unittest.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "components/zoom/zoom_controller.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/prefs/pref_service.h"
 #include "components/zoom/test/zoom_test_utils.h"
-#include "components/zoom/zoom_controller.h"
 #include "components/zoom/zoom_observer.h"
 #include "content/public/browser/host_zoom_map.h"
-#include "content/public/browser/navigation_handle.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/test_utils.h"
 #include "ipc/ipc_message.h"
@@ -52,10 +52,9 @@
       false);
   ZoomChangedWatcher zoom_change_watcher(zoom_controller_.get(),
                                          zoom_change_data);
-  std::unique_ptr<content::NavigationHandle> navigation_handle =
-      content::NavigationHandle::CreateNavigationHandleForTesting(
-          GURL(), rvh()->GetMainFrame(), true);
-  zoom_controller_->DidFinishNavigation(navigation_handle.get());
+  content::MockNavigationHandle handle;
+  handle.set_has_committed(true);
+  zoom_controller_->DidFinishNavigation(&handle);
   zoom_change_watcher.Wait();
 }
 
diff --git a/chrome/test/data/extensions/api_test/serial/real_hardware/background.js b/chrome/test/data/extensions/api_test/serial/real_hardware/background.js
index 354954e..dc89fa79 100644
--- a/chrome/test/data/extensions/api_test/serial/real_hardware/background.js
+++ b/chrome/test/data/extensions/api_test/serial/real_hardware/background.js
@@ -5,8 +5,9 @@
 var testGetDevices = function() {
   var onGetDevices = function(devices) {
     chrome.test.assertTrue(devices.length == 2);
-    chrome.test.assertEq('/dev/fakeserialmojo', devices[0].path);
-    chrome.test.assertEq('\\\\COM800\\', devices[1].path);
+    const array = ['/dev/fakeserialmojo', '\\\\COM800\\'];
+    chrome.test.assertTrue(array.indexOf(devices[0].path) >= 0);
+    chrome.test.assertTrue(array.indexOf(devices[1].path) >= 0);
     chrome.test.succeed();
   }
 
diff --git a/chrome/test/data/pdf/annotations_feature_enabled_test.js b/chrome/test/data/pdf/annotations_feature_enabled_test.js
index 2906bfc..e55ac2c 100644
--- a/chrome/test/data/pdf/annotations_feature_enabled_test.js
+++ b/chrome/test/data/pdf/annotations_feature_enabled_test.js
@@ -76,5 +76,68 @@
         chrome.test.assertEq(expectation.right, actual.right);
       }
     });
+  },
+  function testPenOptions() {
+    testAsync(async () => {
+      // Still in annotation mode after previous test.
+      const inkHost = contentElement();
+      let tool = null;
+      inkHost.ink_.setAnnotationTool = value => tool = value;
+
+      // Pen defaults.
+      document.querySelector('* /deep/ #pen').click();
+      chrome.test.assertEq('pen', tool.tool);
+      chrome.test.assertEq(0.1429, tool.size);
+      chrome.test.assertEq('#000000', tool.color);
+
+
+      // Selected size and color.
+      document.querySelector(
+          '* /deep/ #pen /deep/ #sizes [value="1"]').click();
+      document.querySelector(
+          '* /deep/ #pen /deep/ #colors [value="#00b0ff"]').click();
+      await animationFrame();
+      chrome.test.assertEq('pen', tool.tool);
+      chrome.test.assertEq(1, tool.size);
+      chrome.test.assertEq('#00b0ff', tool.color);
+
+
+      // Eraser defaults.
+      document.querySelector('* /deep/ #eraser').click();
+      chrome.test.assertEq('eraser', tool.tool);
+      chrome.test.assertEq(1, tool.size);
+      chrome.test.assertEq(null, tool.color);
+
+
+      // Pen keeps previous settings.
+      document.querySelector('* /deep/ #pen').click();
+      chrome.test.assertEq('pen', tool.tool);
+      chrome.test.assertEq(1, tool.size);
+      chrome.test.assertEq('#00b0ff', tool.color);
+
+
+      // Highlighter defaults.
+      document.querySelector('* /deep/ #highlighter').click();
+      chrome.test.assertEq('highlighter', tool.tool);
+      chrome.test.assertEq(0.7143, tool.size);
+      chrome.test.assertEq('#ffbc00', tool.color);
+
+
+      // Need to expand to use this color.
+      document.querySelector(
+          '* /deep/ #highlighter /deep/ #colors [value="#d1c4e9"]').click();
+      chrome.test.assertEq('#ffbc00', tool.color);
+
+      // Selected size and expanded color.
+      document.querySelector(
+        '* /deep/ #highlighter /deep/ #sizes [value="1"]').click();
+      document.querySelector(
+        '* /deep/ #highlighter /deep/ #colors #expand').click();
+      document.querySelector(
+        '* /deep/ #highlighter /deep/ #colors [value="#d1c4e9"]').click();
+      chrome.test.assertEq('highlighter', tool.tool);
+      chrome.test.assertEq(1, tool.size);
+      chrome.test.assertEq('#d1c4e9', tool.color);
+    });
   }
 ]);
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index d55e2853..293a2b1 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -174,11 +174,14 @@
   test_type = "unit"
   sources = [
     "../../../browser/resources/md_downloads/search_service_unittest.gtestjs",
+    "../../../browser/resources/print_preview/print_preview_utils_unittest.gtestjs",
     "../../../renderer/resources/extensions/notifications_custom_bindings.gtestjs",
     "../unit/framework_unittest.gtestjs",
   ]
   extra_js_files = [
     "../../../browser/resources/md_downloads/browser_proxy.js",
+    "../../../browser/resources/print_preview/data/measurement_system.js",
+    "../../../browser/resources/print_preview/print_preview_utils.js",
     "../../../browser/resources/md_downloads/search_service.js",
     "../../../renderer/resources/extensions/notifications_custom_bindings.js",
     "../../../renderer/resources/extensions/notifications_test_util.js",
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index e2cec478..b12b561 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -49,6 +49,7 @@
     ":metrics_event_proto",
     ":oobe_config_proto",
     ":power_manager_proto",
+    ":runtime_probe_proto",
     ":seneschal_proto",
     ":smbprovider_proto",
     ":vm_applications_apps_proto",
@@ -186,7 +187,7 @@
     ":chromeos_export",
     "//base",
     "//base:i18n",
-    "//chromeos/dbus:dbus_switches",
+    "//chromeos/dbus:constants",
     "//third_party/icu",
   ]
   sources = [
@@ -561,6 +562,18 @@
   proto_out_dir = "chromeos/dbus/oobe_config"
 }
 
+proto_library("runtime_probe_proto") {
+  sources = [
+    "//third_party/cros_system_api/dbus/runtime_probe/runtime_probe.proto",
+  ]
+
+  # chromeos side uses full runtime, so we don't specify lite runtime in proto
+  # file, instead we specify lite runtime here.
+  cc_generator_options = "lite=true:"
+
+  proto_out_dir = "chromeos/dbus/runtime_probe"
+}
+
 proto_library("seneschal_proto") {
   sources = [
     "//third_party/cros_system_api/dbus/seneschal/seneschal_service.proto",
diff --git a/chromeos/constants/DEPS b/chromeos/constants/DEPS
index 71dc68d..0f487b8 100644
--- a/chromeos/constants/DEPS
+++ b/chromeos/constants/DEPS
@@ -3,6 +3,6 @@
 include_rules = [
   "+base",
   "+chromeos/chromeos_export.h",
-  "+chromeos/dbus/dbus_switches.h",
+  "+chromeos/dbus/constants",
   "+third_party/icu",
 ]
diff --git a/chromeos/constants/chromeos_paths.cc b/chromeos/constants/chromeos_paths.cc
index c647a44..629af0ef 100644
--- a/chromeos/constants/chromeos_paths.cc
+++ b/chromeos/constants/chromeos_paths.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_util.h"
 #include "base/path_service.h"
 #include "base/system/sys_info.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 
 namespace chromeos {
 
@@ -20,15 +21,6 @@
     FILE_PATH_LITERAL("/usr/share/chromium/default_app_order.json");
 #endif  // defined(GOOGLE_CHROME_BUILD)
 
-const base::FilePath::CharType kDefaultUserPolicyKeysDir[] =
-    FILE_PATH_LITERAL("/run/user_policy");
-
-const base::FilePath::CharType kOwnerKeyFileName[] =
-    FILE_PATH_LITERAL("/var/lib/whitelist/owner.key");
-
-const base::FilePath::CharType kInstallAttributesFileName[] =
-    FILE_PATH_LITERAL("/run/lockbox/install_attributes.pb");
-
 const base::FilePath::CharType kMachineHardwareInfoFileName[] =
     FILE_PATH_LITERAL("/tmp/machine-info");
 
@@ -70,15 +62,6 @@
     case FILE_DEFAULT_APP_ORDER:
       *result = base::FilePath(kDefaultAppOrderFileName);
       break;
-    case DIR_USER_POLICY_KEYS:
-      *result = base::FilePath(kDefaultUserPolicyKeysDir);
-      break;
-    case FILE_OWNER_KEY:
-      *result = base::FilePath(kOwnerKeyFileName);
-      break;
-    case FILE_INSTALL_ATTRIBUTES:
-      *result = base::FilePath(kInstallAttributesFileName);
-      break;
     case FILE_MACHINE_INFO:
       *result = base::FilePath(kMachineHardwareInfoFileName);
       break;
@@ -124,25 +107,19 @@
 }  // namespace
 
 void RegisterPathProvider() {
+  dbus_paths::RegisterPathProvider();
   base::PathService::RegisterProvider(PathProvider, PATH_START, PATH_END);
 }
 
 void RegisterStubPathOverrides(const base::FilePath& stubs_dir) {
+  dbus_paths::RegisterStubPathOverrides(stubs_dir);
   CHECK(!base::SysInfo::IsRunningOnChromeOS());
   // Override these paths on the desktop, so that enrollment and cloud policy
   // work and can be tested.
   base::FilePath parent = base::MakeAbsoluteFilePath(stubs_dir);
-  base::PathService::Override(DIR_USER_POLICY_KEYS,
-                              parent.AppendASCII("stub_user_policy"));
   const bool is_absolute = true;
   const bool create = false;
   base::PathService::OverrideAndCreateIfNeeded(
-      FILE_OWNER_KEY, parent.AppendASCII("stub_owner.key"), is_absolute,
-      create);
-  base::PathService::OverrideAndCreateIfNeeded(
-      FILE_INSTALL_ATTRIBUTES, parent.AppendASCII("stub_install_attributes.pb"),
-      is_absolute, create);
-  base::PathService::OverrideAndCreateIfNeeded(
       FILE_MACHINE_INFO, parent.AppendASCII("stub_machine-info"), is_absolute,
       create);
   base::PathService::OverrideAndCreateIfNeeded(
diff --git a/chromeos/constants/chromeos_paths.h b/chromeos/constants/chromeos_paths.h
index 39dc3dfa..3045185 100644
--- a/chromeos/constants/chromeos_paths.h
+++ b/chromeos/constants/chromeos_paths.h
@@ -21,10 +21,6 @@
 
   FILE_DEFAULT_APP_ORDER,   // Full path to the json file that defines the
                             // default app order.
-  DIR_USER_POLICY_KEYS,     // Directory where the session_manager stores
-                            // the user policy keys.
-  FILE_OWNER_KEY,           // Full path to the owner key file.
-  FILE_INSTALL_ATTRIBUTES,  // Full path to the install attributes file.
   FILE_MACHINE_INFO,        // Full path to machine hardware info file.
   FILE_VPD,                 // Full path to VPD file.
   FILE_UPTIME,              // Full path to the file via which the kernel
diff --git a/chromeos/constants/chromeos_switches.h b/chromeos/constants/chromeos_switches.h
index 21ea070c..a8aa7c7 100644
--- a/chromeos/constants/chromeos_switches.h
+++ b/chromeos/constants/chromeos_switches.h
@@ -8,7 +8,7 @@
 #include "base/feature_list.h"
 #include "base/memory/memory_pressure_monitor_chromeos.h"
 #include "chromeos/chromeos_export.h"
-#include "chromeos/dbus/dbus_switches.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 
 namespace chromeos {
 namespace switches {
diff --git a/chromeos/dbus/BUILD.gn b/chromeos/dbus/BUILD.gn
index 8299d8f..8dc3e1af 100644
--- a/chromeos/dbus/BUILD.gn
+++ b/chromeos/dbus/BUILD.gn
@@ -11,7 +11,7 @@
 source_set("dbus") {
   configs += [ "//chromeos:chromeos_implementation" ]
   public_deps = [
-    ":dbus_switches",
+    ":constants",
     "//dbus",
   ]
   deps = [
@@ -20,7 +20,6 @@
     "//chromeos:attestation_proto",
     "//chromeos:authpolicy_proto",
     "//chromeos:biod_proto",
-    "//chromeos:chromeos_constants",
     "//chromeos:chromeos_export",
     "//chromeos:cicerone_proto",
     "//chromeos:concierge_proto",
@@ -29,6 +28,7 @@
     "//chromeos:media_perception_proto",
     "//chromeos:oobe_config_proto",
     "//chromeos:power_manager_proto",
+    "//chromeos:runtime_probe_proto",
     "//chromeos:seneschal_proto",
     "//chromeos:smbprovider_proto",
     "//components/account_id",
@@ -36,9 +36,6 @@
     "//components/policy:cloud_policy_proto_generated_compile",
     "//components/policy/proto",
     "//net",
-    "//skia",
-    "//third_party/icu",
-    "//third_party/protobuf:protobuf_lite",
     "//url",
   ]
   sources = [
@@ -139,6 +136,8 @@
     "fake_permission_broker_client.h",
     "fake_power_manager_client.cc",
     "fake_power_manager_client.h",
+    "fake_runtime_probe_client.cc",
+    "fake_runtime_probe_client.h",
     "fake_seneschal_client.cc",
     "fake_seneschal_client.h",
     "fake_session_manager_client.cc",
@@ -193,6 +192,8 @@
     "power_manager_client.h",
     "power_policy_controller.cc",
     "power_policy_controller.h",
+    "runtime_probe_client.cc",
+    "runtime_probe_client.h",
     "seneschal_client.cc",
     "seneschal_client.h",
     "services/cros_dbus_service.cc",
@@ -236,15 +237,17 @@
   ]
 }
 
-source_set("dbus_switches") {
+source_set("constants") {
   configs += [ "//chromeos:chromeos_implementation" ]
   deps = [
     "//base",
     "//chromeos:chromeos_export",
   ]
   sources = [
-    "dbus_switches.cc",
-    "dbus_switches.h",
+    "constants/dbus_paths.cc",
+    "constants/dbus_paths.h",
+    "constants/dbus_switches.cc",
+    "constants/dbus_switches.h",
   ]
 }
 
@@ -274,7 +277,6 @@
   deps = [
     ":dbus",
     "//base",
-    "//base:i18n",
     "//base/test:test_support",
     "//chromeos:biod_proto",
     "//chromeos:chromeos_constants",
diff --git a/chromeos/dbus/DEPS b/chromeos/dbus/DEPS
index 6ee941f..4724e277 100644
--- a/chromeos/dbus/DEPS
+++ b/chromeos/dbus/DEPS
@@ -15,11 +15,3 @@
   "+third_party/cros_system_api",
   "+url",
 ]
-
-specific_include_rules = {
-  "fake_.*": [
-    # TODO(stevenjb): Remove use of chromeos_paths in fake impls.
-    # https://crbug.com/863439.
-    "+chromeos/constants",
-  ],
-}
diff --git a/chromeos/dbus/cicerone_client.cc b/chromeos/dbus/cicerone_client.cc
index d6fb71d..0b37362 100644
--- a/chromeos/dbus/cicerone_client.cc
+++ b/chromeos/dbus/cicerone_client.cc
@@ -70,6 +70,10 @@
     return is_tremplin_started_signal_connected_;
   }
 
+  bool IsLxdContainerStartingSignalConnected() override {
+    return is_lxd_container_starting_signal_connected_;
+  }
+
   void LaunchContainerApplication(
       const vm_tools::cicerone::LaunchContainerApplicationRequest& request,
       DBusMethodCallback<vm_tools::cicerone::LaunchContainerApplicationResponse>
@@ -346,6 +350,13 @@
                             weak_ptr_factory_.GetWeakPtr()),
         base::BindOnce(&CiceroneClientImpl::OnSignalConnected,
                        weak_ptr_factory_.GetWeakPtr()));
+    cicerone_proxy_->ConnectToSignal(
+        vm_tools::cicerone::kVmCiceroneInterface,
+        vm_tools::cicerone::kLxdContainerStartingSignal,
+        base::BindRepeating(&CiceroneClientImpl::OnLxdContainerStartingSignal,
+                            weak_ptr_factory_.GetWeakPtr()),
+        base::BindOnce(&CiceroneClientImpl::OnSignalConnected,
+                       weak_ptr_factory_.GetWeakPtr()));
   }
 
  private:
@@ -450,6 +461,18 @@
     }
   }
 
+  void OnLxdContainerStartingSignal(dbus::Signal* signal) {
+    vm_tools::cicerone::LxdContainerStartingSignal proto;
+    dbus::MessageReader reader(signal);
+    if (!reader.PopArrayOfBytesAsProto(&proto)) {
+      LOG(ERROR) << "Failed to parse proto from DBus Signal";
+      return;
+    }
+    for (auto& observer : observer_list_) {
+      observer.OnLxdContainerStarting(proto);
+    }
+  }
+
   void OnSignalConnected(const std::string& interface_name,
                          const std::string& signal_name,
                          bool is_connected) {
@@ -475,6 +498,8 @@
       is_lxd_container_downloading_signal_connected_ = is_connected;
     } else if (signal_name == vm_tools::cicerone::kTremplinStartedSignal) {
       is_tremplin_started_signal_connected_ = is_connected;
+    } else if (signal_name == vm_tools::cicerone::kLxdContainerStartingSignal) {
+      is_lxd_container_starting_signal_connected_ = is_connected;
     } else {
       NOTREACHED();
     }
@@ -491,6 +516,7 @@
   bool is_lxd_container_created_signal_connected_ = false;
   bool is_lxd_container_downloading_signal_connected_ = false;
   bool is_tremplin_started_signal_connected_ = false;
+  bool is_lxd_container_starting_signal_connected_ = false;
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
diff --git a/chromeos/dbus/cicerone_client.h b/chromeos/dbus/cicerone_client.h
index aa74506..1ccc49c4 100644
--- a/chromeos/dbus/cicerone_client.h
+++ b/chromeos/dbus/cicerone_client.h
@@ -57,6 +57,12 @@
     virtual void OnTremplinStarted(
         const vm_tools::cicerone::TremplinStartedSignal& signal) = 0;
 
+    // OnLxdContainerStarting is signaled from Cicerone when async container
+    // startup is used. This is necessary if long running file remapping is
+    // required before an old container is safe to use.
+    virtual void OnLxdContainerStarting(
+        const vm_tools::cicerone::LxdContainerStartingSignal& signal) = 0;
+
    protected:
     virtual ~Observer() = default;
   };
@@ -95,6 +101,9 @@
   // StartLxdContainer.
   virtual bool IsTremplinStartedSignalConnected() = 0;
 
+  // This should be true prior to calling StartLxdContainer in async mode
+  virtual bool IsLxdContainerStartingSignalConnected() = 0;
+
   // Launches an application inside a running Container.
   // |callback| is called after the method call finishes.
   virtual void LaunchContainerApplication(
diff --git a/chromeos/dbus/constants/dbus_paths.cc b/chromeos/dbus/constants/dbus_paths.cc
new file mode 100644
index 0000000..6737bb6
--- /dev/null
+++ b/chromeos/dbus/constants/dbus_paths.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2013 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 "chromeos/dbus/constants/dbus_paths.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/system/sys_info.h"
+
+namespace chromeos {
+namespace dbus_paths {
+
+namespace {
+
+constexpr base::FilePath::CharType kDefaultUserPolicyKeysDir[] =
+    FILE_PATH_LITERAL("/run/user_policy");
+
+constexpr base::FilePath::CharType kOwnerKeyFileName[] =
+    FILE_PATH_LITERAL("/var/lib/whitelist/owner.key");
+
+constexpr base::FilePath::CharType kInstallAttributesFileName[] =
+    FILE_PATH_LITERAL("/run/lockbox/install_attributes.pb");
+
+bool PathProvider(int key, base::FilePath* result) {
+  switch (key) {
+    case DIR_USER_POLICY_KEYS:
+      *result = base::FilePath(kDefaultUserPolicyKeysDir);
+      break;
+    case FILE_OWNER_KEY:
+      *result = base::FilePath(kOwnerKeyFileName);
+      break;
+    case FILE_INSTALL_ATTRIBUTES:
+      *result = base::FilePath(kInstallAttributesFileName);
+      break;
+    default:
+      return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+void RegisterPathProvider() {
+  base::PathService::RegisterProvider(PathProvider, PATH_START, PATH_END);
+}
+
+void RegisterStubPathOverrides(const base::FilePath& stubs_dir) {
+  CHECK(!base::SysInfo::IsRunningOnChromeOS());
+
+  // Override these paths when running on Linux, so that enrollment and cloud
+  // policy work correctly and can be tested.
+  base::FilePath parent = base::MakeAbsoluteFilePath(stubs_dir);
+  base::PathService::Override(DIR_USER_POLICY_KEYS,
+                              parent.AppendASCII("stub_user_policy"));
+  const bool is_absolute = true;
+  const bool create = false;
+  base::PathService::OverrideAndCreateIfNeeded(
+      FILE_OWNER_KEY, parent.AppendASCII("stub_owner.key"), is_absolute,
+      create);
+  base::PathService::OverrideAndCreateIfNeeded(
+      FILE_INSTALL_ATTRIBUTES, parent.AppendASCII("stub_install_attributes.pb"),
+      is_absolute, create);
+}
+
+}  // namespace dbus_paths
+}  // namespace chromeos
diff --git a/chromeos/dbus/constants/dbus_paths.h b/chromeos/dbus/constants/dbus_paths.h
new file mode 100644
index 0000000..949aac5
--- /dev/null
+++ b/chromeos/dbus/constants/dbus_paths.h
@@ -0,0 +1,42 @@
+// Copyright 2018 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 CHROMEOS_DBUS_CONSTANTS_DBUS_PATHS_H_
+#define CHROMEOS_DBUS_CONSTANTS_DBUS_PATHS_H_
+
+#include "chromeos/chromeos_export.h"
+
+namespace base {
+class FilePath;
+}
+
+// This file declares path keys for the chromeos/dbus module.  These can be used
+// with the PathService to access various special directories and files.
+
+namespace chromeos {
+namespace dbus_paths {
+
+enum {
+  PATH_START = 7200,
+
+  DIR_USER_POLICY_KEYS,     // Directory where the session_manager stores
+                            // the user policy keys.
+  FILE_OWNER_KEY,           // Full path to the owner key file.
+  FILE_INSTALL_ATTRIBUTES,  // Full path to the install attributes file.
+
+  PATH_END
+};
+
+// Call once to register the provider for the path keys defined above.
+CHROMEOS_EXPORT void RegisterPathProvider();
+
+// Overrides some of the paths listed above so that those files can be used
+// when not running on ChromeOS. The stubs files will be relative to
+// |stubs_dir|. It is not valid to call this when running on ChromeOS.
+CHROMEOS_EXPORT void RegisterStubPathOverrides(const base::FilePath& stubs_dir);
+
+}  // namespace dbus_paths
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_CONSTANTS_DBUS_PATHS_H_
diff --git a/chromeos/dbus/dbus_switches.cc b/chromeos/dbus/constants/dbus_switches.cc
similarity index 97%
rename from chromeos/dbus/dbus_switches.cc
rename to chromeos/dbus/constants/dbus_switches.cc
index 404b6225..ac2d80e 100644
--- a/chromeos/dbus/dbus_switches.cc
+++ b/chromeos/dbus/constants/dbus_switches.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/dbus/dbus_switches.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 
 namespace chromeos {
 namespace switches {
diff --git a/chromeos/dbus/dbus_switches.h b/chromeos/dbus/constants/dbus_switches.h
similarity index 80%
rename from chromeos/dbus/dbus_switches.h
rename to chromeos/dbus/constants/dbus_switches.h
index bfb08d9..3d817d15 100644
--- a/chromeos/dbus/dbus_switches.h
+++ b/chromeos/dbus/constants/dbus_switches.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_DBUS_DBUS_SWITCHES_H_
-#define CHROMEOS_DBUS_DBUS_SWITCHES_H_
+#ifndef CHROMEOS_DBUS_CONSTANTS_DBUS_SWITCHES_H_
+#define CHROMEOS_DBUS_CONSTANTS_DBUS_SWITCHES_H_
 
 #include "chromeos/chromeos_export.h"
 
@@ -20,4 +20,4 @@
 }  // namespace switches
 }  // namespace chromeos
 
-#endif  // CHROMEOS_DBUS_DBUS_SWITCHES_H_
+#endif  // CHROMEOS_DBUS_CONSTANTS_DBUS_SWITCHES_H_
diff --git a/chromeos/dbus/cryptohome_client.cc b/chromeos/dbus/cryptohome_client.cc
index e98c15b4..333b867 100644
--- a/chromeos/dbus/cryptohome_client.cc
+++ b/chromeos/dbus/cryptohome_client.cc
@@ -19,9 +19,9 @@
 #include "base/observer_list.h"
 #include "base/optional.h"
 #include "chromeos/dbus/blocking_method_caller.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/dbus/cryptohome/key.pb.h"
 #include "chromeos/dbus/cryptohome/rpc.pb.h"
-#include "chromeos/dbus/dbus_switches.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
 #include "dbus/object_path.h"
diff --git a/chromeos/dbus/dbus_clients_browser.cc b/chromeos/dbus/dbus_clients_browser.cc
index 2c0931bc..33420e3 100644
--- a/chromeos/dbus/dbus_clients_browser.cc
+++ b/chromeos/dbus/dbus_clients_browser.cc
@@ -33,6 +33,7 @@
 #include "chromeos/dbus/fake_lorgnette_manager_client.h"
 #include "chromeos/dbus/fake_media_analytics_client.h"
 #include "chromeos/dbus/fake_oobe_configuration_client.h"
+#include "chromeos/dbus/fake_runtime_probe_client.h"
 #include "chromeos/dbus/fake_seneschal_client.h"
 #include "chromeos/dbus/fake_smb_provider_client.h"
 #include "chromeos/dbus/fake_virtual_file_provider_client.h"
@@ -41,6 +42,7 @@
 #include "chromeos/dbus/lorgnette_manager_client.h"
 #include "chromeos/dbus/media_analytics_client.h"
 #include "chromeos/dbus/oobe_configuration_client.h"
+#include "chromeos/dbus/runtime_probe_client.h"
 #include "chromeos/dbus/seneschal_client.h"
 #include "chromeos/dbus/smb_provider_client.h"
 #include "chromeos/dbus/virtual_file_provider_client.h"
@@ -130,6 +132,11 @@
     oobe_configuration_client_.reset(new FakeOobeConfigurationClient);
 
   if (use_real_clients)
+    runtime_probe_client_ = RuntimeProbeClient::Create();
+  else
+    runtime_probe_client_ = std::make_unique<FakeRuntimeProbeClient>();
+
+  if (use_real_clients)
     seneschal_client_ = SeneschalClient::Create();
   else
     seneschal_client_ = std::make_unique<FakeSeneschalClient>();
@@ -166,6 +173,7 @@
   lorgnette_manager_client_->Init(system_bus);
   media_analytics_client_->Init(system_bus);
   oobe_configuration_client_->Init(system_bus);
+  runtime_probe_client_->Init(system_bus);
   seneschal_client_->Init(system_bus);
   smb_provider_client_->Init(system_bus);
   virtual_file_provider_client_->Init(system_bus);
diff --git a/chromeos/dbus/dbus_clients_browser.h b/chromeos/dbus/dbus_clients_browser.h
index b6b0b07..9e6698a 100644
--- a/chromeos/dbus/dbus_clients_browser.h
+++ b/chromeos/dbus/dbus_clients_browser.h
@@ -32,6 +32,7 @@
 class LorgnetteManagerClient;
 class MediaAnalyticsClient;
 class OobeConfigurationClient;
+class RuntimeProbeClient;
 class SeneschalClient;
 class SmbProviderClient;
 class VirtualFileProviderClient;
@@ -67,6 +68,7 @@
   std::unique_ptr<LorgnetteManagerClient> lorgnette_manager_client_;
   std::unique_ptr<MediaAnalyticsClient> media_analytics_client_;
   std::unique_ptr<OobeConfigurationClient> oobe_configuration_client_;
+  std::unique_ptr<RuntimeProbeClient> runtime_probe_client_;
   std::unique_ptr<SeneschalClient> seneschal_client_;
   std::unique_ptr<SmbProviderClient> smb_provider_client_;
   std::unique_ptr<VirtualFileProviderClient> virtual_file_provider_client_;
diff --git a/chromeos/dbus/dbus_clients_common.cc b/chromeos/dbus/dbus_clients_common.cc
index dcc89af..ed45093 100644
--- a/chromeos/dbus/dbus_clients_common.cc
+++ b/chromeos/dbus/dbus_clients_common.cc
@@ -7,10 +7,10 @@
 #include "base/command_line.h"
 #include "chromeos/dbus/biod/biod_client.h"
 #include "chromeos/dbus/cec_service_client.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/dbus/cras_audio_client.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_client_implementation_type.h"
-#include "chromeos/dbus/dbus_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cras_audio_client.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc
index 4e03c4e5c..1a55f5a2d 100644
--- a/chromeos/dbus/dbus_thread_manager.cc
+++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -19,13 +19,13 @@
 #include "chromeos/dbus/cec_service_client.h"
 #include "chromeos/dbus/cicerone_client.h"
 #include "chromeos/dbus/concierge_client.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/dbus/cras_audio_client.h"
 #include "chromeos/dbus/cros_disks_client.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_client.h"
 #include "chromeos/dbus/dbus_clients_browser.h"
 #include "chromeos/dbus/dbus_clients_common.h"
-#include "chromeos/dbus/dbus_switches.h"
 #include "chromeos/dbus/debug_daemon_client.h"
 #include "chromeos/dbus/easy_unlock_client.h"
 #include "chromeos/dbus/gsm_sms_client.h"
diff --git a/chromeos/dbus/fake_cicerone_client.cc b/chromeos/dbus/fake_cicerone_client.cc
index 2afb333..38a7bae 100644
--- a/chromeos/dbus/fake_cicerone_client.cc
+++ b/chromeos/dbus/fake_cicerone_client.cc
@@ -27,7 +27,7 @@
       vm_tools::cicerone::CreateLxdContainerResponse::CREATING);
 
   start_lxd_container_response_.set_status(
-      vm_tools::cicerone::StartLxdContainerResponse::STARTED);
+      vm_tools::cicerone::StartLxdContainerResponse::STARTING);
 
   setup_lxd_container_user_response_.set_status(
       vm_tools::cicerone::SetUpLxdContainerUserResponse::SUCCESS);
@@ -63,6 +63,10 @@
   return is_tremplin_started_signal_connected_;
 }
 
+bool FakeCiceroneClient::IsLxdContainerStartingSignalConnected() {
+  return is_lxd_container_starting_signal_connected_;
+}
+
 bool FakeCiceroneClient::IsInstallLinuxPackageProgressSignalConnected() {
   return is_install_linux_package_progress_signal_connected_;
 }
@@ -146,6 +150,18 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(std::move(callback), start_lxd_container_response_));
+  if (request.async()) {
+    // Trigger CiceroneClient::Observer::NotifyLxdContainerStartingSignal.
+    vm_tools::cicerone::LxdContainerStartingSignal signal;
+    signal.set_owner_id(request.owner_id());
+    signal.set_vm_name(request.vm_name());
+    signal.set_container_name(request.container_name());
+    signal.set_status(lxd_container_starting_signal_status_);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&FakeCiceroneClient::NotifyLxdContainerStarting,
+                       base::Unretained(this), std::move(signal)));
+  }
 }
 
 void FakeCiceroneClient::GetLxdContainerUsername(
@@ -197,4 +213,11 @@
   }
 }
 
+void FakeCiceroneClient::NotifyLxdContainerStarting(
+    const vm_tools::cicerone::LxdContainerStartingSignal& proto) {
+  for (auto& observer : observer_list_) {
+    observer.OnLxdContainerStarting(proto);
+  }
+}
+
 }  // namespace chromeos
diff --git a/chromeos/dbus/fake_cicerone_client.h b/chromeos/dbus/fake_cicerone_client.h
index fa62094..6596ac34 100644
--- a/chromeos/dbus/fake_cicerone_client.h
+++ b/chromeos/dbus/fake_cicerone_client.h
@@ -47,6 +47,9 @@
   // StartLxdContainer.
   bool IsTremplinStartedSignalConnected() override;
 
+  // This should be true prior to calling StartLxdContainer in async mode
+  bool IsLxdContainerStartingSignalConnected() override;
+
   // Fake version of the method that launches an application inside a running
   // Container. |callback| is called after the method call finishes.
   void LaunchContainerApplication(
@@ -147,15 +150,22 @@
       vm_tools::cicerone::LxdContainerCreatedSignal_Status status) {
     lxd_container_created_signal_status_ = status;
   }
+
   // Set LxdContainerDownloadingSignalConnected state
   void set_lxd_container_downloading_signal_connected(bool connected) {
     is_lxd_container_downloading_signal_connected_ = connected;
   }
+
   // Set TremplinStartedSignalConnected state
   void set_tremplin_started_signal_connected(bool connected) {
     is_tremplin_started_signal_connected_ = connected;
   }
 
+  // Set LxdContainerStartingSignalConnected state
+  void set_lxd_container_starting_signal_connected(bool connected) {
+    is_lxd_container_starting_signal_connected_ = connected;
+  }
+
   void set_launch_container_application_response(
       const vm_tools::cicerone::LaunchContainerApplicationResponse&
           launch_container_application_response) {
@@ -219,6 +229,8 @@
       const vm_tools::cicerone::ContainerStartedSignal& signal);
   void NotifyTremplinStarted(
       const vm_tools::cicerone::TremplinStartedSignal& signal);
+  void NotifyLxdContainerStarting(
+      const vm_tools::cicerone::LxdContainerStartingSignal& signal);
 
  protected:
   void Init(dbus::Bus* bus) override {}
@@ -231,10 +243,14 @@
   bool is_lxd_container_created_signal_connected_ = true;
   bool is_lxd_container_downloading_signal_connected_ = true;
   bool is_tremplin_started_signal_connected_ = true;
+  bool is_lxd_container_starting_signal_connected_ = true;
 
   vm_tools::cicerone::LxdContainerCreatedSignal_Status
       lxd_container_created_signal_status_ =
           vm_tools::cicerone::LxdContainerCreatedSignal::CREATED;
+  vm_tools::cicerone::LxdContainerStartingSignal_Status
+      lxd_container_starting_signal_status_ =
+          vm_tools::cicerone::LxdContainerStartingSignal::STARTED;
 
   vm_tools::cicerone::LaunchContainerApplicationResponse
       launch_container_application_response_;
diff --git a/chromeos/dbus/fake_cryptohome_client.cc b/chromeos/dbus/fake_cryptohome_client.cc
index c1aca52..a3c0e71 100644
--- a/chromeos/dbus/fake_cryptohome_client.cc
+++ b/chromeos/dbus/fake_cryptohome_client.cc
@@ -18,8 +18,8 @@
 #include "base/stl_util.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chromeos/constants/chromeos_paths.h"
 #include "chromeos/dbus/attestation/attestation.pb.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome/key.pb.h"
 #include "chromeos/dbus/cryptohome/rpc.pb.h"
 #include "chromeos/dbus/util/account_identifier_operators.h"
@@ -50,9 +50,9 @@
       system_salt_(GetStubSystemSalt()),
       weak_ptr_factory_(this) {
   base::FilePath cache_path;
-  locked_ =
-      base::PathService::Get(chromeos::FILE_INSTALL_ATTRIBUTES, &cache_path) &&
-      base::PathExists(cache_path);
+  locked_ = base::PathService::Get(dbus_paths::FILE_INSTALL_ATTRIBUTES,
+                                   &cache_path) &&
+            base::PathExists(cache_path);
   if (locked_)
     LoadInstallAttributes();
 }
@@ -264,8 +264,10 @@
   // browser is restarted. This is used for ease of development when device
   // enrollment is required.
   base::FilePath cache_path;
-  if (!base::PathService::Get(chromeos::FILE_INSTALL_ATTRIBUTES, &cache_path))
+  if (!base::PathService::Get(dbus_paths::FILE_INSTALL_ATTRIBUTES,
+                              &cache_path)) {
     return false;
+  }
 
   cryptohome::SerializedInstallAttributes install_attrs_proto;
   for (const auto& it : install_attrs_) {
@@ -839,7 +841,8 @@
 bool FakeCryptohomeClient::LoadInstallAttributes() {
   base::FilePath cache_file;
   const bool file_exists =
-      base::PathService::Get(FILE_INSTALL_ATTRIBUTES, &cache_file) &&
+      base::PathService::Get(dbus_paths::FILE_INSTALL_ATTRIBUTES,
+                             &cache_file) &&
       base::PathExists(cache_file);
   DCHECK(file_exists);
   // Mostly copied from chrome/browser/chromeos/settings/install_attributes.cc.
diff --git a/chromeos/dbus/fake_debug_daemon_client.cc b/chromeos/dbus/fake_debug_daemon_client.cc
index 978abe6..ebb2ac7 100644
--- a/chromeos/dbus/fake_debug_daemon_client.cc
+++ b/chromeos/dbus/fake_debug_daemon_client.cc
@@ -19,7 +19,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chromeos/dbus/dbus_switches.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 
 namespace {
 
diff --git a/chromeos/dbus/fake_oobe_configuration_client.cc b/chromeos/dbus/fake_oobe_configuration_client.cc
index b44dc4e..fe43bad1 100644
--- a/chromeos/dbus/fake_oobe_configuration_client.cc
+++ b/chromeos/dbus/fake_oobe_configuration_client.cc
@@ -12,7 +12,7 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/task/post_task.h"
-#include "chromeos/dbus/dbus_switches.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 
 namespace {
 
diff --git a/chromeos/dbus/fake_runtime_probe_client.cc b/chromeos/dbus/fake_runtime_probe_client.cc
new file mode 100644
index 0000000..b356154c
--- /dev/null
+++ b/chromeos/dbus/fake_runtime_probe_client.cc
@@ -0,0 +1,26 @@
+// Copyright 2018 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 "chromeos/dbus/fake_runtime_probe_client.h"
+
+#include <utility>
+
+#include "base/threading/thread_task_runner_handle.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+
+namespace chromeos {
+
+FakeRuntimeProbeClient::FakeRuntimeProbeClient() : weak_ptr_factory_(this) {}
+
+FakeRuntimeProbeClient::~FakeRuntimeProbeClient() = default;
+
+void FakeRuntimeProbeClient::ProbeCategories(
+    const runtime_probe::ProbeRequest& request,
+    RuntimeProbeCallback callback) {
+  runtime_probe::ProbeResult result;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), result));
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/fake_runtime_probe_client.h b/chromeos/dbus/fake_runtime_probe_client.h
new file mode 100644
index 0000000..a92cd9f
--- /dev/null
+++ b/chromeos/dbus/fake_runtime_probe_client.h
@@ -0,0 +1,38 @@
+// Copyright 2018 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 CHROMEOS_DBUS_FAKE_RUNTIME_PROBE_CLIENT_H_
+#define CHROMEOS_DBUS_FAKE_RUNTIME_PROBE_CLIENT_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "chromeos/dbus/runtime_probe_client.h"
+
+namespace chromeos {
+
+// FakeRuntimeProbeClient is a light mock of RuntimeProbeClient used for
+// used for tests and when running ChromeOS build on Linux.
+class CHROMEOS_EXPORT FakeRuntimeProbeClient : public RuntimeProbeClient {
+ public:
+  FakeRuntimeProbeClient();
+  ~FakeRuntimeProbeClient() override;
+
+  // RuntimeProbeClient overrides:
+  void ProbeCategories(const runtime_probe::ProbeRequest& request,
+                       RuntimeProbeCallback callback) override;
+
+ protected:
+  void Init(dbus::Bus* bus) override {}
+
+ private:
+  // Note: This should remain the last member so it'll be destroyed and
+  // invalidate its weak pointers before any other members are destroyed.
+  base::WeakPtrFactory<FakeRuntimeProbeClient> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeRuntimeProbeClient);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_FAKE_RUNTIME_PROBE_CLIENT_H_
diff --git a/chromeos/dbus/fake_session_manager_client.cc b/chromeos/dbus/fake_session_manager_client.cc
index 30308a1..b1f9b03e 100644
--- a/chromeos/dbus/fake_session_manager_client.cc
+++ b/chromeos/dbus/fake_session_manager_client.cc
@@ -19,7 +19,7 @@
 #include "base/strings/string_util.h"
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chromeos/constants/chromeos_paths.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/login_manager/policy_descriptor.pb.h"
 #include "chromeos/dbus/util/account_identifier_operators.h"
@@ -171,7 +171,8 @@
   switch (descriptor.account_type()) {
     case login_manager::ACCOUNT_TYPE_DEVICE: {
       base::FilePath owner_key_path;
-      CHECK(base::PathService::Get(chromeos::FILE_OWNER_KEY, &owner_key_path));
+      CHECK(
+          base::PathService::Get(dbus_paths::FILE_OWNER_KEY, &owner_key_path));
       if (key_path)
         *key_path = owner_key_path;
       return owner_key_path.DirName().Append(relative_policy_path);
@@ -181,7 +182,8 @@
     case login_manager::ACCOUNT_TYPE_SESSIONLESS_USER:
     case login_manager::ACCOUNT_TYPE_DEVICE_LOCAL_ACCOUNT: {
       base::FilePath base_path;
-      CHECK(base::PathService::Get(chromeos::DIR_USER_POLICY_KEYS, &base_path));
+      CHECK(
+          base::PathService::Get(dbus_paths::DIR_USER_POLICY_KEYS, &base_path));
       if (key_path) {
         *key_path = base_path.Append(relative_policy_path.DirName())
                         .AppendASCII(kStubPerAccountPolicyKeyFileName);
@@ -515,7 +517,7 @@
     StateKeysCallback callback) {
   if (policy_storage_ == PolicyStorageType::kOnDisk) {
     base::FilePath owner_key_path;
-    CHECK(base::PathService::Get(chromeos::FILE_OWNER_KEY, &owner_key_path));
+    CHECK(base::PathService::Get(dbus_paths::FILE_OWNER_KEY, &owner_key_path));
     const base::FilePath state_keys_path =
         owner_key_path.DirName().AppendASCII(kStubStateKeysFileName);
     base::PostTaskWithTraitsAndReplyWithResult(
diff --git a/chromeos/dbus/fake_shill_manager_client.cc b/chromeos/dbus/fake_shill_manager_client.cc
index 489a89e8..44c4a06 100644
--- a/chromeos/dbus/fake_shill_manager_client.cc
+++ b/chromeos/dbus/fake_shill_manager_client.cc
@@ -19,7 +19,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chromeos/dbus/dbus_switches.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_shill_device_client.h"
 #include "chromeos/dbus/shill_device_client.h"
diff --git a/chromeos/dbus/fake_sms_client.cc b/chromeos/dbus/fake_sms_client.cc
index fc47ec1..3fd69c1 100644
--- a/chromeos/dbus/fake_sms_client.cc
+++ b/chromeos/dbus/fake_sms_client.cc
@@ -12,7 +12,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
-#include "chromeos/dbus/dbus_switches.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/dbus/fake_sms_client.h"
 #include "dbus/object_path.h"
 
diff --git a/chromeos/dbus/power_manager_client.cc b/chromeos/dbus/power_manager_client.cc
index 2500390..d4574c6 100644
--- a/chromeos/dbus/power_manager_client.cc
+++ b/chromeos/dbus/power_manager_client.cc
@@ -22,7 +22,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/platform_thread.h"
 #include "base/timer/timer.h"
-#include "chromeos/dbus/dbus_switches.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/dbus/fake_power_manager_client.h"
 #include "chromeos/dbus/power_manager/backlight.pb.h"
 #include "chromeos/dbus/power_manager/idle.pb.h"
diff --git a/chromeos/dbus/runtime_probe_client.cc b/chromeos/dbus/runtime_probe_client.cc
new file mode 100644
index 0000000..1bc277460
--- /dev/null
+++ b/chromeos/dbus/runtime_probe_client.cc
@@ -0,0 +1,90 @@
+// Copyright 2018 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 "chromeos/dbus/runtime_probe_client.h"
+
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/observer_list.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "third_party/cros_system_api/dbus/runtime_probe/dbus-constants.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+class RuntimeProbeClientImpl : public RuntimeProbeClient {
+ public:
+  RuntimeProbeClientImpl() : weak_ptr_factory_(this) {}
+
+  ~RuntimeProbeClientImpl() override = default;
+
+  // RuntimeProbeClient override:
+  void ProbeCategories(const runtime_probe::ProbeRequest& request,
+                       RuntimeProbeCallback callback) override {
+    dbus::MethodCall method_call(runtime_probe::kRuntimeProbeInterfaceName,
+                                 runtime_probe::kProbeCategoriesMethod);
+    dbus::MessageWriter writer(&method_call);
+
+    if (!writer.AppendProtoAsArrayOfBytes(request)) {
+      LOG(ERROR) << "Failed to encode ProbeRequest protobuf";
+      std::move(callback).Run(base::nullopt);
+      return;
+    }
+    proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&RuntimeProbeClientImpl::OnProbeCategories,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
+ protected:
+  void Init(dbus::Bus* bus) override {
+    proxy_ = bus->GetObjectProxy(
+        runtime_probe::kRuntimeProbeServiceName,
+        dbus::ObjectPath(runtime_probe::kRuntimeProbeServicePath));
+    if (!proxy_) {
+      LOG(ERROR) << "Unable to get dbus proxy for "
+                 << runtime_probe::kRuntimeProbeServiceName;
+    }
+  }
+
+ private:
+  void OnProbeCategories(RuntimeProbeCallback callback,
+                         dbus::Response* response) {
+    if (!response) {
+      std::move(callback).Run(base::nullopt);
+      return;
+    }
+    runtime_probe::ProbeResult response_proto;
+    dbus::MessageReader reader(response);
+    if (!reader.PopArrayOfBytesAsProto(&response_proto)) {
+      LOG(ERROR) << "Failed to parse proto from " << response->GetMember();
+      std::move(callback).Run(base::nullopt);
+      return;
+    }
+    std::move(callback).Run(response_proto);
+  }
+
+  dbus::ObjectProxy* proxy_ = nullptr;
+
+  // Note: This should remain the last member so it'll be destroyed and
+  // invalidate its weak pointers before any other members are destroyed.
+  base::WeakPtrFactory<RuntimeProbeClientImpl> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(RuntimeProbeClientImpl);
+};
+
+RuntimeProbeClient::RuntimeProbeClient() = default;
+
+RuntimeProbeClient::~RuntimeProbeClient() = default;
+
+std::unique_ptr<RuntimeProbeClient> RuntimeProbeClient::Create() {
+  return std::make_unique<RuntimeProbeClientImpl>();
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/runtime_probe_client.h b/chromeos/dbus/runtime_probe_client.h
new file mode 100644
index 0000000..96a7934
--- /dev/null
+++ b/chromeos/dbus/runtime_probe_client.h
@@ -0,0 +1,42 @@
+// Copyright 2018 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 CHROMEOS_DBUS_RUNTIME_PROBE_CLIENT_H_
+#define CHROMEOS_DBUS_RUNTIME_PROBE_CLIENT_H_
+
+#include "base/files/scoped_file.h"
+#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/dbus_client.h"
+#include "chromeos/dbus/dbus_method_call_status.h"
+#include "chromeos/dbus/runtime_probe/runtime_probe.pb.h"
+#include "dbus/object_proxy.h"
+
+namespace chromeos {
+
+// RuntimeProbeClient is used to communicate with Runtime Probe, which provides
+// data for hardware telemetry.
+class CHROMEOS_EXPORT RuntimeProbeClient : public DBusClient {
+ public:
+  using RuntimeProbeCallback = DBusMethodCallback<runtime_probe::ProbeResult>;
+
+  // Creates an instance of RuntimeProbeClient.
+  static std::unique_ptr<RuntimeProbeClient> Create();
+
+  ~RuntimeProbeClient() override;
+
+  // Probes categories.
+  virtual void ProbeCategories(const runtime_probe::ProbeRequest& request,
+                               RuntimeProbeCallback callback) = 0;
+
+ protected:
+  // Create() should be used instead.
+  RuntimeProbeClient();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RuntimeProbeClient);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_RUNTIME_PROBE_CLIENT_H_
diff --git a/chromeos/dbus/update_engine_client.cc b/chromeos/dbus/update_engine_client.cc
index 9787d52..0bc947d8 100644
--- a/chromeos/dbus/update_engine_client.cc
+++ b/chromeos/dbus/update_engine_client.cc
@@ -19,7 +19,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chromeos/dbus/dbus_switches.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/dbus/util/version_loader.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
diff --git a/chromeos/settings/install_attributes.cc b/chromeos/settings/install_attributes.cc
index ef05598..a6ca9c5 100644
--- a/chromeos/settings/install_attributes.cc
+++ b/chromeos/settings/install_attributes.cc
@@ -20,7 +20,7 @@
 #include "base/system/sys_info.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
-#include "chromeos/constants/chromeos_paths.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome/rpc.pb.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/util/tpm_util.h"
@@ -81,7 +81,7 @@
   g_install_attributes =
       new InstallAttributes(DBusThreadManager::Get()->GetCryptohomeClient());
   base::FilePath install_attrs_file;
-  CHECK(base::PathService::Get(chromeos::FILE_INSTALL_ATTRIBUTES,
+  CHECK(base::PathService::Get(dbus_paths::FILE_INSTALL_ATTRIBUTES,
                                &install_attrs_file));
   g_install_attributes->Init(install_attrs_file);
 }
diff --git a/chromeos/settings/install_attributes_unittest.cc b/chromeos/settings/install_attributes_unittest.cc
index a89b034..70e1e1a 100644
--- a/chromeos/settings/install_attributes_unittest.cc
+++ b/chromeos/settings/install_attributes_unittest.cc
@@ -15,7 +15,7 @@
 #include "base/run_loop.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_task_environment.h"
-#include "chromeos/constants/chromeos_paths.h"
+#include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome/rpc.pb.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -51,7 +51,7 @@
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     ASSERT_TRUE(base::PathService::OverrideAndCreateIfNeeded(
-        FILE_INSTALL_ATTRIBUTES, GetTempPath(), true, false));
+        dbus_paths::FILE_INSTALL_ATTRIBUTES, GetTempPath(), true, false));
     DBusThreadManager::Initialize();
     install_attributes_ = std::make_unique<InstallAttributes>(
         DBusThreadManager::Get()->GetCryptohomeClient());
diff --git a/components/account_id/account_id.cc b/components/account_id/account_id.cc
index c422c39d..fb32283a 100644
--- a/components/account_id/account_id.cc
+++ b/components/account_id/account_id.cc
@@ -333,10 +333,10 @@
   return AccountId::EmptyAccountId::GetInstance()->user_id;
 }
 
-namespace BASE_HASH_NAMESPACE {
+namespace std {
 
 std::size_t hash<AccountId>::operator()(const AccountId& user_id) const {
   return hash<std::string>()(user_id.GetUserEmail());
 }
 
-}  // namespace BASE_HASH_NAMESPACE
+}  // namespace std
diff --git a/components/account_id/account_id.h b/components/account_id/account_id.h
index 2de8448..a54b85ab 100644
--- a/components/account_id/account_id.h
+++ b/components/account_id/account_id.h
@@ -116,7 +116,7 @@
 // Returns a reference to a singleton.
 const AccountId& EmptyAccountId();
 
-namespace BASE_HASH_NAMESPACE {
+namespace std {
 
 // Implement hashing of AccountId, so it can be used as a key in STL containers.
 template <>
@@ -124,6 +124,6 @@
   std::size_t operator()(const AccountId& user_id) const;
 };
 
-}  // namespace BASE_HASH_NAMESPACE
+}  // namespace std
 
 #endif  // COMPONENTS_ACCOUNT_ID_ACCOUNT_ID_H_
diff --git a/components/autofill/content/browser/content_autofill_driver_unittest.cc b/components/autofill/content/browser/content_autofill_driver_unittest.cc
index 76597c0..1a08f64b 100644
--- a/components/autofill/content/browser/content_autofill_driver_unittest.cc
+++ b/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -21,11 +21,11 @@
 #include "components/autofill/core/common/autofill_switches.h"
 #include "components/autofill/core/common/form_data_predictions.h"
 #include "content/public/browser/browser_context.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/ssl_status.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/frame_navigate_params.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/test_renderer_host.h"
 #include "mojo/public/cpp/bindings/associated_binding_set.h"
 #include "net/base/net_errors.h"
@@ -303,10 +303,10 @@
   }
 
   void Navigate(bool same_document) {
-    std::unique_ptr<content::NavigationHandle> navigation_handle =
-        content::NavigationHandle::CreateNavigationHandleForTesting(
-            GURL(), main_rfh(), /*committed=*/true, net::OK, same_document);
-    driver_->DidNavigateMainFrame(navigation_handle.get());
+    content::MockNavigationHandle navigation_handle(GURL(), main_rfh());
+    navigation_handle.set_has_committed(true);
+    navigation_handle.set_is_same_document(same_document);
+    driver_->DidNavigateMainFrame(&navigation_handle);
   }
 
  protected:
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index 0beac09..bc09293 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -1415,8 +1415,11 @@
     FormData* form,
     FormFieldData* field) {
   form->origin = GetCanonicalOriginForDocument(document);
-  if (!document.Body().IsNull())
+  if (!document.Body().IsNull()) {
+    SCOPED_UMA_HISTOGRAM_TIMER(
+        "PasswordManager.ButtonTitlePerformance.NoFormTag");
     form->button_titles = InferButtonTitlesForForm(document.Body());
+  }
   if (document.GetFrame() && document.GetFrame()->Top()) {
     form->main_frame_origin = document.GetFrame()->Top()->GetSecurityOrigin();
   } else {
@@ -1793,7 +1796,11 @@
   form->unique_renderer_id = form_element.UniqueRendererFormId();
   form->origin = GetCanonicalOriginForDocument(frame->GetDocument());
   form->action = GetCanonicalActionForForm(form_element);
-  form->button_titles = InferButtonTitlesForForm(form_element);
+  {
+    SCOPED_UMA_HISTOGRAM_TIMER(
+        "PasswordManager.ButtonTitlePerformance.HasFormTag");
+    form->button_titles = InferButtonTitlesForForm(form_element);
+  }
   if (frame->Top()) {
     form->main_frame_origin = frame->Top()->GetSecurityOrigin();
   } else {
diff --git a/components/autofill/core/browser/form_data_importer_unittest.cc b/components/autofill/core/browser/form_data_importer_unittest.cc
index 2cdcea7..865c90a 100644
--- a/components/autofill/core/browser/form_data_importer_unittest.cc
+++ b/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -75,6 +75,7 @@
   ~PersonalDataLoadedObserverMock() override {}
 
   MOCK_METHOD0(OnPersonalDataChanged, void());
+  MOCK_METHOD0(OnPersonalDataFinishedProfileTasks, void());
 };
 
 template <typename T>
@@ -128,10 +129,7 @@
     personal_data_manager_->AddObserver(&personal_data_observer_);
     personal_data_manager_->OnSyncServiceInitialized(nullptr);
 
-    base::RunLoop run_loop;
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-        .WillOnce(QuitMessageLoop(&run_loop));
-    run_loop.Run();
+    WaitForOnPersonalDataChanged();
   }
 
   void EnableWalletCardImport() {
@@ -196,11 +194,7 @@
     personal_data_manager_->OnAcceptedLocalCreditCardSave(
         *imported_credit_card);
 
-    base::RunLoop run_loop;
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-        .WillOnce(QuitMessageLoop(&run_loop));
-    run_loop.Run();
-
+    WaitForOnPersonalDataChanged();
     CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
     test::SetCreditCardInfo(&expected, exp_name, exp_cc_num, exp_cc_month,
                             exp_cc_year, "");
@@ -212,8 +206,10 @@
 
   void WaitForOnPersonalDataChanged() {
     base::RunLoop run_loop;
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
         .WillOnce(QuitMessageLoop(&run_loop));
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .Times(testing::AnyNumber());
     run_loop.Run();
   }
 
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 409bb94..a4cbe059 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -305,6 +305,11 @@
   if (!database_helper_->GetLocalDatabase()) {
     return;
   }
+
+  database_helper_->GetLocalDatabase()->SetAutofillProfileChangedCallback(
+      base::BindRepeating(&PersonalDataManager::OnAutofillProfileChanged,
+                          weak_factory_.GetWeakPtr()));
+
   LoadProfiles();
   LoadCreditCards();
   LoadPaymentsCustomerData();
@@ -629,14 +634,13 @@
     profile->RecordAndLogUse();
 
     if (profile->record_type() == AutofillProfile::LOCAL_PROFILE) {
-      database_helper_->GetLocalDatabase()->UpdateAutofillProfile(*profile);
+      UpdateProfileInDB(*profile);
     } else if (profile->record_type() == AutofillProfile::SERVER_PROFILE) {
       // TODO(crbug.com/864519): Update this once addresses support account
       // storage, and also use the server database.
       database_helper_->GetLocalDatabase()->UpdateServerAddressMetadata(
           *profile);
     }
-
     Refresh();
   }
 }
@@ -648,39 +652,16 @@
   if (is_off_the_record_)
     return;
 
-  if (profile.IsEmpty(app_locale_))
-    return;
-
-  // Don't add an existing profile.
-  if (FindByGUID<AutofillProfile>(web_profiles_, profile.guid()))
-    return;
-
   if (!database_helper_->GetLocalDatabase())
     return;
 
-  // Don't add a duplicate.
-  if (FindByContents(web_profiles_, profile))
-    return;
-
-  // Add the new profile to the web database.
-  database_helper_->GetLocalDatabase()->AddAutofillProfile(profile);
-
-  // Refresh our local cache and send notifications to observers.
-  Refresh();
+  AddProfileToDB(profile);
 }
 
 void PersonalDataManager::UpdateProfile(const AutofillProfile& profile) {
   if (is_off_the_record_)
     return;
 
-  AutofillProfile* existing_profile = GetProfileByGUID(profile.guid());
-  if (!existing_profile)
-    return;
-
-  // Don't overwrite the origin for a profile that is already stored.
-  if (existing_profile->EqualsSansOrigin(profile))
-    return;
-
   if (profile.IsEmpty(app_locale_)) {
     RemoveByGUID(profile.guid());
     return;
@@ -689,11 +670,7 @@
   if (!database_helper_->GetLocalDatabase())
     return;
 
-  // Make the update.
-  database_helper_->GetLocalDatabase()->UpdateAutofillProfile(profile);
-
-  // Refresh our local cache and send notifications to observers.
-  Refresh();
+  UpdateProfileInDB(profile);
 }
 
 AutofillProfile* PersonalDataManager::GetProfileByGUID(
@@ -927,9 +904,9 @@
 }
 
 void PersonalDataManager::
-    RemoveAutofillProfileByGUIDAndBlankCreditCardReferecne(
+    RemoveAutofillProfileByGUIDAndBlankCreditCardReference(
         const std::string& guid) {
-  database_helper_->GetLocalDatabase()->RemoveAutofillProfile(guid);
+  RemoveProfileFromDB(guid);
 
   // Reset the billing_address_id of any card that refered to this profile.
   for (CreditCard* credit_card : GetCreditCards()) {
@@ -952,23 +929,17 @@
   if (is_off_the_record_)
     return;
 
-  bool is_credit_card = FindByGUID<CreditCard>(local_credit_cards_, guid);
-  bool is_profile =
-      !is_credit_card && FindByGUID<AutofillProfile>(web_profiles_, guid);
-  if (!is_credit_card && !is_profile)
-    return;
-
   if (!database_helper_->GetLocalDatabase())
     return;
 
+  bool is_credit_card = FindByGUID<CreditCard>(local_credit_cards_, guid);
   if (is_credit_card) {
     database_helper_->GetLocalDatabase()->RemoveCreditCard(guid);
+    // Refresh our local cache and send notifications to observers.
+    Refresh();
   } else {
-    RemoveAutofillProfileByGUIDAndBlankCreditCardReferecne(guid);
+    RemoveAutofillProfileByGUIDAndBlankCreditCardReference(guid);
   }
-
-  // Refresh our local cache and send notifications to observers.
-  Refresh();
 }
 
 CreditCard* PersonalDataManager::GetCreditCardByGUID(const std::string& guid) {
@@ -1011,9 +982,9 @@
 
 void PersonalDataManager::UpdateProfilesServerValidityMapsIfNeeded(
     const std::vector<AutofillProfile*>& profiles) {
-  if (!profiles_server_validities_need_update)
+  if (!profiles_server_validities_need_update_)
     return;
-  profiles_server_validities_need_update = false;
+  profiles_server_validities_need_update_ = false;
   for (auto* profile : profiles) {
     profile->UpdateServerValidityMap(GetProfileValidityByGUID(profile->guid()));
   }
@@ -1092,7 +1063,6 @@
   LoadProfiles();
   LoadCreditCards();
   LoadPaymentsCustomerData();
-  profiles_server_validities_need_update = true;
 }
 
 std::vector<AutofillProfile*> PersonalDataManager::GetProfilesToSuggest()
@@ -1363,20 +1333,13 @@
 }
 
 void PersonalDataManager::ClearProfileNonSettingsOrigins() {
-  bool has_updated = false;
-
   for (AutofillProfile* profile : GetProfiles()) {
     if (profile->origin() != kSettingsOrigin && !profile->origin().empty()) {
       profile->set_origin(std::string());
-      database_helper_->GetLocalDatabase()->UpdateAutofillProfile(*profile);
-      has_updated = true;
+      UpdateProfileInDB(*profile);
     }
   }
 
-  // Refresh the local cache and send notifications to observers if a changed
-  // was made.
-  if (has_updated)
-    Refresh();
 }
 
 void PersonalDataManager::ClearCreditCardNonSettingsOrigins() {
@@ -1404,7 +1367,6 @@
   if (pref_service_->GetBoolean(prefs::kAutofillJapanCityFieldMigrated))
     return;
 
-  bool has_updated = false;
   base::string16 japan_country_code = base::ASCIIToUTF16("JP");
   base::string16 line_separator = base::ASCIIToUTF16("\n");
   for (AutofillProfile* profile : GetProfiles()) {
@@ -1420,16 +1382,10 @@
       profile->SetRawInfo(ADDRESS_HOME_CITY, base::string16());
 
       // Make the update.
-      database_helper_->GetLocalDatabase()->UpdateAutofillProfile(*profile);
-      has_updated = true;
+      UpdateProfileInDB(*profile);
     }
   }
 
-  // Refresh the local cache and send notifications to observers if a change was
-  // made.
-  if (has_updated)
-    Refresh();
-
   // Set the pref so that this migration is never run again.
   pref_service_->SetBoolean(prefs::kAutofillJapanCityFieldMigrated, true);
 }
@@ -1452,7 +1408,7 @@
     const std::string& guid) {
   static const ProfileValidityMap& empty_validity_map = ProfileValidityMap();
   if (!synced_profile_validity_) {
-    profiles_server_validities_need_update = true;
+    profiles_server_validities_need_update_ = true;
     synced_profile_validity_ = std::make_unique<UserProfileValidityMap>();
     if (!synced_profile_validity_->ParseFromString(
             ::autofill::prefs::GetAllProfilesValidityMapsEncodedString(
@@ -1605,31 +1561,25 @@
 void PersonalDataManager::SetProfiles(std::vector<AutofillProfile>* profiles) {
   if (is_off_the_record_)
     return;
-
-  // Remove empty profiles from input.
-  base::EraseIf(*profiles, IsEmptyFunctor<AutofillProfile>(app_locale_));
-
   if (!database_helper_->GetLocalDatabase())
     return;
 
+  ClearOnGoingProfileChanges();
+
   // Any profiles that are not in the new profile list should be removed from
-  // the web database.
+  // the web database
   for (const auto& it : web_profiles_) {
     if (!FindByGUID<AutofillProfile>(*profiles, it->guid()))
-      database_helper_->GetLocalDatabase()->RemoveAutofillProfile(it->guid());
+      RemoveProfileFromDB(it->guid());
   }
 
-  // Update the web database with the existing profiles.
+  // Update the web database with the new and existing profiles.
   for (const AutofillProfile& it : *profiles) {
-    if (FindByGUID<AutofillProfile>(web_profiles_, it.guid()))
-      database_helper_->GetLocalDatabase()->UpdateAutofillProfile(it);
-  }
-
-  // Add the new profiles to the web database.  Don't add a duplicate.
-  for (const AutofillProfile& it : *profiles) {
-    if (!FindByGUID<AutofillProfile>(web_profiles_, it.guid()) &&
-        !FindByContents(web_profiles_, it))
-      database_helper_->GetLocalDatabase()->AddAutofillProfile(it);
+    if (FindByGUID<AutofillProfile>(web_profiles_, it.guid())) {
+      UpdateProfileInDB(it);
+    } else {
+      AddProfileToDB(it);
+    }
   }
 
   // Copy in the new profiles.
@@ -1637,9 +1587,6 @@
   for (const AutofillProfile& it : *profiles) {
     web_profiles_.push_back(std::make_unique<AutofillProfile>(it));
   }
-
-  // Refresh our local cache and send notifications to observers.
-  Refresh();
 }
 
 void PersonalDataManager::SetCreditCards(
@@ -1775,8 +1722,13 @@
 }
 
 void PersonalDataManager::NotifyPersonalDataChanged() {
-  for (PersonalDataManagerObserver& observer : observers_)
+  bool profile_changes_are_on_going = ProfileChangesAreOnGoing();
+  for (PersonalDataManagerObserver& observer : observers_) {
     observer.OnPersonalDataChanged();
+    if (!profile_changes_are_on_going) {
+      observer.OnPersonalDataFinishedProfileTasks();
+    }
+  }
 
   // If new data was synced, try to convert new server profiles and update
   // server cards.
@@ -1992,6 +1944,53 @@
       /*opted_in=*/true);
 }
 
+void PersonalDataManager::OnAutofillProfileChanged(
+    const AutofillProfileDeepChange& change) {
+  const auto& guid = change.key();
+  const auto& change_type = change.type();
+  const auto& profile = change.profile();
+
+  DCHECK(guid == profile.guid());
+
+  // Happens only in tests.
+  if (!ProfileChangesAreOnGoing(guid)) {
+    DVLOG(1) << "Received an unexpected response from database.";
+    return;
+  }
+
+  const auto* existing_profile = GetProfileByGUID(guid);
+  const bool profile_exists = (existing_profile != nullptr);
+  switch (change_type) {
+    case AutofillProfileChange::ADD:
+      profiles_server_validities_need_update_ = true;
+      if (!profile_exists && !FindByContents(web_profiles_, profile)) {
+        web_profiles_.push_back(std::make_unique<AutofillProfile>(profile));
+      }
+      break;
+    case AutofillProfileChange::UPDATE:
+      profiles_server_validities_need_update_ = true;
+      if (profile_exists && !existing_profile->EqualsSansOrigin(profile)) {
+        web_profiles_.erase(
+            FindElementByGUID<AutofillProfile>(web_profiles_, guid));
+        web_profiles_.push_back(std::make_unique<AutofillProfile>(profile));
+      }
+      break;
+    case AutofillProfileChange::REMOVE:
+      if (profile_exists) {
+        web_profiles_.erase(
+            FindElementByGUID<AutofillProfile>(web_profiles_, guid));
+      }
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  ongoing_profile_changes_[guid].pop();
+
+  NotifyPersonalDataChanged();
+  HandleNextProfileChange(guid);
+}
+
 void PersonalDataManager::LogServerCardLinkClicked() const {
   AutofillMetrics::LogServerCardLinkClicked(GetSyncSigninState());
 }
@@ -2132,11 +2131,10 @@
   for (const auto& profile : web_profiles_) {
     // If the profile was set to be deleted, remove it from the database.
     if (profiles_to_delete.count(profile.get())) {
-      database_helper_->GetLocalDatabase()->RemoveAutofillProfile(
-          profile->guid());
+      RemoveProfileFromDB(profile->guid());
     } else {
       // Otherwise, update the profile in the database.
-      database_helper_->GetLocalDatabase()->UpdateAutofillProfile(*profile);
+      UpdateProfileInDB(*profile);
     }
   }
 
@@ -2145,10 +2143,6 @@
   // Set the pref to the current major version.
   pref_service_->SetInteger(prefs::kAutofillLastVersionDeduped,
                             current_major_version);
-
-  // Refresh the local cache and send notifications to observers.
-  Refresh();
-
   return true;
 }
 
@@ -2278,6 +2272,7 @@
             *credit_card);
     }
   }
+  Refresh();
 }
 
 void PersonalDataManager::ConvertWalletAddressesAndUpdateWalletCards() {
@@ -2318,7 +2313,6 @@
     // TODO(crbug.com/915229): Remove once the investigation is over.
     if (has_converted_addresses)
       DLOG(WARNING) << this << " conversion of addresses done";
-    Refresh();
   }
 }
 
@@ -2523,7 +2517,7 @@
   size_t num_deleted_addresses = guids_to_delete.size();
 
   for (auto const guid : guids_to_delete) {
-    RemoveAutofillProfileByGUIDAndBlankCreditCardReferecne(guid);
+    RemoveAutofillProfileByGUIDAndBlankCreditCardReference(guid);
   }
 
   if (num_deleted_addresses > 0) {
@@ -2570,7 +2564,111 @@
 
 void PersonalDataManager::ResetProfileValidity() {
   synced_profile_validity_.reset();
-  profiles_server_validities_need_update = true;
+  profiles_server_validities_need_update_ = true;
+}
+
+void PersonalDataManager::AddProfileToDB(const AutofillProfile& profile) {
+  // Add the new profile to the web database.
+  if (profile.IsEmpty(app_locale_)) {
+    NotifyPersonalDataChanged();
+    return;
+  }
+
+  if (!ProfileChangesAreOnGoing(profile.guid())) {
+    // Don't add an existing/empty profile.
+    if (FindByGUID<AutofillProfile>(web_profiles_, profile.guid()) ||
+        FindByContents(web_profiles_, profile)) {
+      NotifyPersonalDataChanged();
+      return;
+    }
+    database_helper_->GetLocalDatabase()->AddAutofillProfile(profile);
+  }
+
+  ongoing_profile_changes_[profile.guid()].push(
+      AutofillProfileDeepChange(AutofillProfileChange::ADD, profile));
+}
+
+void PersonalDataManager::UpdateProfileInDB(const AutofillProfile& profile) {
+  // Update the profile in the web database.
+  if (!ProfileChangesAreOnGoing(profile.guid())) {
+    database_helper_->GetLocalDatabase()->UpdateAutofillProfile(profile);
+  }
+  ongoing_profile_changes_[profile.guid()].push(
+      AutofillProfileDeepChange(AutofillProfileChange::UPDATE, profile));
+}
+
+void PersonalDataManager::RemoveProfileFromDB(const std::string& guid) {
+  bool profile_exists = FindByGUID<AutofillProfile>(web_profiles_, guid);
+  if (!profile_exists && !ProfileChangesAreOnGoing(guid)) {
+    NotifyPersonalDataChanged();
+    return;
+  }
+
+  if (!ProfileChangesAreOnGoing(guid))
+    database_helper_->GetLocalDatabase()->RemoveAutofillProfile(guid);
+  ongoing_profile_changes_[guid].push(
+      AutofillProfileDeepChange(AutofillProfileChange::REMOVE, guid));
+}
+
+void PersonalDataManager::HandleNextProfileChange(const std::string& guid) {
+  if (!ProfileChangesAreOnGoing(guid))
+    return;
+
+  const auto& change_type = ongoing_profile_changes_[guid].front().type();
+  const auto* existing_profile = GetProfileByGUID(guid);
+  const bool profile_exists = (existing_profile != nullptr);
+  const auto& profile = ongoing_profile_changes_[guid].front().profile();
+
+  DCHECK(guid == profile.guid());
+
+  if (change_type == AutofillProfileChange::REMOVE) {
+    if (!profile_exists) {
+      ongoing_profile_changes_[guid].pop();
+      NotifyPersonalDataChanged();
+      HandleNextProfileChange(guid);
+      return;
+    }
+    database_helper_->GetLocalDatabase()->RemoveAutofillProfile(guid);
+    return;
+  }
+
+  if (change_type == AutofillProfileChange::ADD) {
+    if (profile_exists || FindByContents(web_profiles_, profile)) {
+      ongoing_profile_changes_[guid].pop();
+      NotifyPersonalDataChanged();
+      HandleNextProfileChange(guid);
+      return;
+    }
+    database_helper_->GetLocalDatabase()->AddAutofillProfile(profile);
+    return;
+  }
+
+  if (!profile_exists || existing_profile->EqualsSansOrigin(profile)) {
+    ongoing_profile_changes_[guid].pop();
+    NotifyPersonalDataChanged();
+    HandleNextProfileChange(guid);
+    return;
+  }
+  database_helper_->GetLocalDatabase()->UpdateAutofillProfile(profile);
+}
+
+bool PersonalDataManager::ProfileChangesAreOnGoing(const std::string& guid) {
+  return ongoing_profile_changes_.find(guid) !=
+             ongoing_profile_changes_.end() &&
+         !ongoing_profile_changes_[guid].empty();
+}
+
+bool PersonalDataManager::ProfileChangesAreOnGoing() {
+  for (auto task : ongoing_profile_changes_) {
+    if (ProfileChangesAreOnGoing(task.first)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void PersonalDataManager::ClearOnGoingProfileChanges() {
+  ongoing_profile_changes_.clear();
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index f8bd2d11..8e0c4dc 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -28,6 +28,7 @@
 #include "components/autofill/core/browser/suggestion.h"
 #include "components/autofill/core/browser/sync_utils.h"
 #include "components/autofill/core/browser/test_data_creator.h"
+#include "components/autofill/core/browser/webdata/autofill_change.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
 #include "components/history/core/browser/history_service_observer.h"
@@ -395,6 +396,9 @@
   // Records the sync transport consent if the user is in sync transport mode.
   virtual void OnUserAcceptedUpstreamOffer();
 
+  // Triggered when a profile is added/updated/removed on db.
+  void OnAutofillProfileChanged(const AutofillProfileDeepChange& change);
+
  protected:
   // Only PersonalDataManagerFactory and certain tests can create instances of
   // PersonalDataManager.
@@ -498,15 +502,9 @@
                               std::vector<AutofillProfile>* profiles);
 
   // Sets |web_profiles_| to the contents of |profiles| and updates the web
-  // database by adding, updating and removing profiles.
-  // The relationship between this and Refresh is subtle.
-  // A call to |SetProfiles| could include out-of-date data that may conflict
-  // if we didn't refresh-to-latest before an Autofill window was opened for
-  // editing. |SetProfiles| is implemented to make a "best effort" to apply the
-  // changes, but in extremely rare edge cases it is possible not all of the
-  // updates in |profiles| make it to the DB.  This is why SetProfiles will
-  // invoke Refresh after finishing, to ensure we get into a
-  // consistent state.  See Refresh for details.
+  // database by adding, updating and removing profiles. |web_profiles_| need to
+  // be updated at the end of the function, since some tasks cannot tolerate
+  // database delays.
   virtual void SetProfiles(std::vector<AutofillProfile>* profiles);
 
   // Sets |credit_cards_| to the contents of |credit_cards| and updates the web
@@ -618,7 +616,7 @@
   base::ObserverList<PersonalDataManagerObserver>::Unchecked observers_;
 
   // |profile_valditiies_need_update| whenever the profile validities are out of
-  bool profiles_server_validities_need_update = true;
+  bool profiles_server_validities_need_update_ = true;
 
  private:
   // Saves |imported_credit_card| to the WebDB if it exists. Returns the guid of
@@ -716,7 +714,7 @@
   // card's billing address if that address is used by any credit cards.
   // The method does not refresh, this allows multiple removal with one
   // refreshing in the end.
-  void RemoveAutofillProfileByGUIDAndBlankCreditCardReferecne(
+  void RemoveAutofillProfileByGUIDAndBlankCreditCardReference(
       const std::string& guid);
 
   // Returns true if an address can be deleted in a major version upgrade.
@@ -735,6 +733,22 @@
   // Resets |synced_profile_validity_|.
   void ResetProfileValidity();
 
+  // Add/Update/Remove profiles on DB.
+  void AddProfileToDB(const AutofillProfile& profile);
+  void UpdateProfileInDB(const AutofillProfile& profile);
+  void RemoveProfileFromDB(const std::string& guid);
+
+  // Look at the next profile change for profile with guid = |guid|, and handle
+  // it.
+  void HandleNextProfileChange(const std::string& guid);
+  // returns true if there is any profile change that's still on going.
+  bool ProfileChangesAreOnGoing();
+  // returns true if there is any ongoing change for profile with guid = |guid|
+  // that's still on going.
+  bool ProfileChangesAreOnGoing(const std::string& guid);
+  // Clear |ongoing_profile_changes_|.
+  void ClearOnGoingProfileChanges();
+
   const std::string app_locale_;
 
   // The default country code for new addresses.
@@ -761,6 +775,10 @@
   // |profile_validities_need_update| whenever this is changed.
   std::unique_ptr<UserProfileValidityMap> synced_profile_validity_;
 
+  // A timely ordered list of on going changes for each profile.
+  std::unordered_map<std::string, std::queue<AutofillProfileDeepChange>>
+      ongoing_profile_changes_;
+
   // The client side profile validator.
   AutofillProfileValidator* client_profile_validator_ = nullptr;
 
diff --git a/components/autofill/core/browser/personal_data_manager_observer.h b/components/autofill/core/browser/personal_data_manager_observer.h
index e948d3f..d09bc934 100644
--- a/components/autofill/core/browser/personal_data_manager_observer.h
+++ b/components/autofill/core/browser/personal_data_manager_observer.h
@@ -18,6 +18,10 @@
   // Called when there is insufficient data to fill a form. Used for testing.
   virtual void OnInsufficientFormData() {}
 
+  // Notifies the observer that the PersonalDataManager has no more tasks to
+  // handle.
+  virtual void OnPersonalDataFinishedProfileTasks() {}
+
  protected:
   virtual ~PersonalDataManagerObserver() {}
 };
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index bfc241d2..b6a42765 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -72,8 +72,8 @@
 const base::Time kSomeLaterTime = base::Time::FromDoubleT(1000);
 const base::Time kMuchLaterTime = base::Time::FromDoubleT(5000);
 
-ACTION(QuitMainMessageLoop) {
-  base::RunLoop::QuitCurrentWhenIdleDeprecated();
+ACTION_P(QuitMessageLoop, loop) {
+  loop->Quit();
 }
 
 class PersonalDataLoadedObserverMock : public PersonalDataManagerObserver {
@@ -82,6 +82,7 @@
   ~PersonalDataLoadedObserverMock() override {}
 
   MOCK_METHOD0(OnPersonalDataChanged, void());
+  MOCK_METHOD0(OnPersonalDataFinishedProfileTasks, void());
 };
 
 class PersonalDataManagerMock : public PersonalDataManager {
@@ -193,6 +194,7 @@
   void ResetPersonalDataManager(UserMode user_mode,
                                 bool use_sync_transport_mode) {
     bool is_incognito = (user_mode == USER_MODE_INCOGNITO);
+
     personal_data_.reset(new PersonalDataManagerMock("en"));
     personal_data_->Init(
         scoped_refptr<AutofillWebDataService>(profile_database_service_),
@@ -213,10 +215,7 @@
     personal_data_->OnSyncServiceInitialized(&sync_service_);
     personal_data_->OnStateChanged(&sync_service_);
 
-    // Verify that the web database has been updated and the notification sent.
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-        .WillRepeatedly(QuitMainMessageLoop());
-    base::RunLoop().Run();
+    WaitForOnPersonalDataChanged();
   }
 
   void ResetPersonalDataManager(UserMode user_mode) {
@@ -226,6 +225,7 @@
   void ResetProfiles() {
     std::vector<AutofillProfile> empty_profiles;
     personal_data_->SetProfiles(&empty_profiles);
+    WaitForOnPersonalDataChanged();
   }
 
   bool TurnOnSyncFeature() WARN_UNUSED_RESULT {
@@ -253,11 +253,7 @@
     test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
                          "johnwayne@me.xyz", "Fox", "123 Zoo St", "unit 5",
                          "Hollywood", "CA", "91601", "US", "12345678910");
-    personal_data_->AddProfile(profile);
-
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-        .WillOnce(QuitMainMessageLoop());
-    base::RunLoop().Run();
+    AddProfileToPersonalDataManager(profile);
 
     ASSERT_EQ(1U, personal_data_->GetProfiles().size());
   }
@@ -298,10 +294,7 @@
                             "1");
     personal_data_->AddCreditCard(credit_card2);
 
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-        .WillOnce(QuitMainMessageLoop());
-    base::RunLoop().Run();
-
+    WaitOnceForOnPersonalDataChanged();
     ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
   }
 
@@ -318,9 +311,7 @@
     masked_server_card.set_server_id("masked_id");
     masked_server_card.set_use_count(15);
     personal_data_->AddFullServerCreditCard(masked_server_card);
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-        .WillOnce(QuitMainMessageLoop());
-    base::RunLoop().Run();
+    WaitOnceForOnPersonalDataChanged();
     ASSERT_EQ(1U, personal_data_->GetCreditCards().size());
 
 // Cards are automatically remasked on Linux since full server cards are not
@@ -349,10 +340,7 @@
     local_card.set_use_count(5);
     personal_data_->AddCreditCard(local_card);
 
-    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-        .WillOnce(QuitMainMessageLoop());
-    base::RunLoop().Run();
-
+    WaitOnceForOnPersonalDataChanged();
     EXPECT_EQ(3U, personal_data_->GetCreditCards().size());
   }
 
@@ -379,9 +367,8 @@
     AutofillProfile profile0(test::GetFullProfile());
     profile0.set_use_date(AutofillClock::Now() -
                           base::TimeDelta::FromDays(400));
-    personal_data_->AddProfile(profile0);
+    AddProfileToPersonalDataManager(profile0);
 
-    WaitForOnPersonalDataChanged();
     EXPECT_EQ(1U, personal_data_->GetProfiles().size());
   }
 
@@ -390,6 +377,38 @@
                                                   : account_autofill_table_;
   }
 
+  void AddProfileToPersonalDataManager(const AutofillProfile& profile) {
+    base::RunLoop run_loop;
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+        .WillOnce(QuitMessageLoop(&run_loop));
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .Times(testing::AnyNumber());
+    personal_data_->AddProfile(profile);
+    run_loop.Run();
+  }
+
+  void UpdateProfileOnPersonalDataManager(const AutofillProfile& profile) {
+    base::RunLoop run_loop;
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+        .WillOnce(QuitMessageLoop(&run_loop));
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .Times(testing::AnyNumber());
+
+    personal_data_->UpdateProfile(profile);
+    run_loop.Run();
+  }
+
+  void RemoveByGUIDFromPersonalDataManager(const std::string& guid) {
+    base::RunLoop run_loop;
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+        .WillOnce(QuitMessageLoop(&run_loop));
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+        .Times(testing::AnyNumber());
+
+    personal_data_->RemoveByGUID(guid);
+    run_loop.Run();
+  }
+
   void SetServerCards(const std::vector<CreditCard>& server_cards) {
     test::SetServerCreditCards(GetServerDataTable(), server_cards);
   }
@@ -400,9 +419,20 @@
 
   // Verifies that the web database has been updated and the notification sent.
   void WaitForOnPersonalDataChanged() {
+    base::RunLoop run_loop;
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+        .WillOnce(QuitMessageLoop(&run_loop));
     EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-        .WillRepeatedly(QuitMainMessageLoop());
-    base::RunLoop().Run();
+        .Times(testing::AnyNumber());
+    run_loop.Run();
+  }
+
+  void WaitOnceForOnPersonalDataChanged() {
+    base::RunLoop run_loop;
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+        .WillOnce(QuitMessageLoop(&run_loop));
+    EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+    run_loop.Run();
   }
 
   void ExpectOnValidated(AutofillProfile* profile) {
@@ -462,11 +492,9 @@
   // Add profile0 to the database.
   AutofillProfile profile0(test::GetFullProfile());
   profile0.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("j@s.com"));
-  personal_data_->AddProfile(profile0);
-
+  AddProfileToPersonalDataManager(profile0);
   // Reload the database.
   ResetPersonalDataManager(USER_MODE_NORMAL);
-
   // Verify the addition.
   const std::vector<AutofillProfile*>& results1 = personal_data_->GetProfiles();
   ASSERT_EQ(1U, results1.size());
@@ -475,7 +503,8 @@
   // Add profile with identical values.  Duplicates should not get saved.
   AutofillProfile profile0a = profile0;
   profile0a.set_guid(base::GenerateGUID());
-  personal_data_->AddProfile(profile0a);
+
+  AddProfileToPersonalDataManager(profile0a);
 
   // Reload the database.
   ResetPersonalDataManager(USER_MODE_NORMAL);
@@ -493,7 +522,7 @@
   // Add the different profile.  This should save as a separate profile.
   // Note that if this same profile was "merged" it would collapse to one
   // profile with a multi-valued entry for email.
-  personal_data_->AddProfile(profile1);
+  AddProfileToPersonalDataManager(profile1);
 
   // Reload the database.
   ResetPersonalDataManager(USER_MODE_NORMAL);
@@ -505,17 +534,44 @@
   ExpectSameElements(profiles, personal_data_->GetProfiles());
 }
 
-// TODO(crbug.com/909730): If you add a profile and then remove it right away,
-// the profile will not be removed, but it should.
-TEST_F(PersonalDataManagerTest, AddRemoveProfile) {
+// Adding, updating, removing operations without waiting in between.
+TEST_F(PersonalDataManagerTest, AddRemoveUpdateProfileSequence) {
   AutofillProfile profile(test::GetFullProfile());
 
   personal_data_->AddProfile(profile);
   personal_data_->RemoveByGUID(profile.guid());
-
   WaitForOnPersonalDataChanged();
+
   auto profiles = personal_data_->GetProfiles();
-  ASSERT_EQ(1U, profiles.size());  // the correct size is 0.
+  ASSERT_EQ(0U, profiles.size());
+
+  personal_data_->AddProfile(profile);
+  personal_data_->RemoveByGUID(profile.guid());
+  personal_data_->RemoveByGUID(profile.guid());
+  WaitForOnPersonalDataChanged();
+  profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(0U, profiles.size());
+
+  personal_data_->AddProfile(profile);
+  profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("new@email.com"));
+  personal_data_->UpdateProfile(profile);
+  WaitForOnPersonalDataChanged();
+
+  profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(1U, profiles.size());
+  EXPECT_EQ(profiles[0]->GetRawInfo(EMAIL_ADDRESS),
+            base::ASCIIToUTF16("new@email.com"));
+
+  profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("new@email.com"));
+  personal_data_->UpdateProfile(profile);
+  profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("newer@email.com"));
+  personal_data_->UpdateProfile(profile);
+  WaitForOnPersonalDataChanged();
+
+  profiles = personal_data_->GetProfiles();
+  ASSERT_EQ(1U, profiles.size());
+  EXPECT_EQ(profiles[0]->GetRawInfo(EMAIL_ADDRESS),
+            base::ASCIIToUTF16("newer@email.com"));
 }
 
 // Test that a new profile has its basic information set.
@@ -527,7 +583,7 @@
   // Add a profile to the database.
   AutofillProfile profile(test::GetFullProfile());
   profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("j@s.com"));
-  personal_data_->AddProfile(profile);
+  AddProfileToPersonalDataManager(profile);
 
   // Reload the database.
   ResetPersonalDataManager(USER_MODE_NORMAL);
@@ -686,7 +742,7 @@
   std::vector<AutofillProfile> profiles;
   profiles.push_back(with_invalid);
   personal_data_->SetProfiles(&profiles);
-
+  WaitForOnPersonalDataChanged();
   ASSERT_EQ(1u, personal_data_->GetProfiles().size());
   AutofillProfile profile = *personal_data_->GetProfiles()[0];
   ASSERT_NE(without_invalid.GetRawInfo(PHONE_HOME_WHOLE_NUMBER),
@@ -699,6 +755,7 @@
   EXPECT_NE(base::Time(), profile.modification_date());
 
   personal_data_->SaveImportedProfile(profile);
+  WaitForOnPersonalDataChanged();
   const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
   ASSERT_EQ(1U, profiles.size());
   EXPECT_GT(base::TimeDelta::FromMilliseconds(500),
@@ -722,10 +779,8 @@
                        "Orlando", "FL", "32801", "US", "19482937549");
 
   // Add two test profiles to the database.
-  personal_data_->AddProfile(profile0);
-  personal_data_->AddProfile(profile1);
-
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(profile0);
+  AddProfileToPersonalDataManager(profile1);
 
   std::vector<AutofillProfile*> profiles;
   profiles.push_back(&profile0);
@@ -734,11 +789,9 @@
 
   // Update, remove, and add.
   profile0.SetRawInfo(NAME_FIRST, base::ASCIIToUTF16("John"));
-  personal_data_->UpdateProfile(profile0);
-  personal_data_->RemoveByGUID(profile1.guid());
-  personal_data_->AddProfile(profile2);
-
-  WaitForOnPersonalDataChanged();
+  UpdateProfileOnPersonalDataManager(profile0);
+  RemoveByGUIDFromPersonalDataManager(profile1.guid());
+  AddProfileToPersonalDataManager(profile2);
 
   profiles.clear();
   profiles.push_back(&profile0);
@@ -784,7 +837,7 @@
   // Update, remove, and add.
   credit_card0.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Joe"));
   personal_data_->UpdateCreditCard(credit_card0);
-  personal_data_->RemoveByGUID(credit_card1.guid());
+  RemoveByGUIDFromPersonalDataManager(credit_card1.guid());
   personal_data_->AddCreditCard(credit_card2);
 
   WaitForOnPersonalDataChanged();
@@ -812,13 +865,8 @@
   credit_card3.set_record_type(CreditCard::FULL_SERVER_CARD);
   credit_card3.set_server_id("server_id");
 
-  // Verify that the web database has been updated and the notification sent.
-  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-      .WillOnce(QuitMainMessageLoop());
-
   personal_data_->AddFullServerCreditCard(credit_card3);
-
-  base::RunLoop().Run();
+  WaitForOnPersonalDataChanged();
 
   cards.push_back(&credit_card3);
   ExpectSameElements(cards, personal_data_->GetCreditCards());
@@ -957,7 +1005,7 @@
   EXPECT_FALSE(credit_card.IsVerified());
 
   // Add the data to the database.
-  personal_data_->AddProfile(profile);
+  AddProfileToPersonalDataManager(profile);
   personal_data_->AddCreditCard(credit_card);
 
   WaitForOnPersonalDataChanged();
@@ -979,7 +1027,7 @@
   EXPECT_TRUE(profile.IsVerified());
   EXPECT_TRUE(credit_card.IsVerified());
 
-  personal_data_->UpdateProfile(profile);
+  UpdateProfileOnPersonalDataManager(profile);
   personal_data_->UpdateCreditCard(credit_card);
 
   // Note: No refresh, as no update is expected.
@@ -998,7 +1046,7 @@
   profile.SetRawInfo(NAME_FIRST, base::ASCIIToUTF16("John"));
   credit_card.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Joe"));
 
-  personal_data_->UpdateProfile(profile);
+  UpdateProfileOnPersonalDataManager(profile);
   personal_data_->UpdateCreditCard(credit_card);
 
   WaitForOnPersonalDataChanged();
@@ -1059,13 +1107,10 @@
                           "378282246310005" /* American Express */, "04",
                           "2999", "1");
 
-  // Verify that the web database has been updated and the notification sent.
-  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-      .WillOnce(QuitMainMessageLoop());
 
   personal_data_->AddFullServerCreditCard(server_card);
 
-  base::RunLoop().Run();
+  WaitForOnPersonalDataChanged();
 
   ASSERT_EQ(1U, personal_data_->GetCreditCards().size());
   EXPECT_EQ(CreditCard::MASKED_SERVER_CARD,
@@ -1182,10 +1227,8 @@
                           "1");
 
   // Add two test profiles to the database.
-  personal_data_->AddProfile(profile0);
-  personal_data_->AddProfile(profile1);
-
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(profile0);
+  AddProfileToPersonalDataManager(profile1);
 
   std::vector<AutofillProfile*> profiles;
   profiles.push_back(&profile0);
@@ -1221,9 +1264,7 @@
                        "");
 
   // Add the profile0 to the db.
-  personal_data_->AddProfile(profile0);
-
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(profile0);
 
   // Verify that we've loaded the profiles from the web database.
   const std::vector<AutofillProfile*>& results2 = personal_data_->GetProfiles();
@@ -1234,9 +1275,7 @@
   AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "z", "", "", "", "", "", "", "", "", "", "",
                        "");
-  personal_data_->AddProfile(profile1);
-
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(profile1);
 
   // Make sure the two profiles have different GUIDs, both valid.
   const std::vector<AutofillProfile*>& results3 = personal_data_->GetProfiles();
@@ -1289,9 +1328,7 @@
                        "");
 
   // Add the empty profile to the database.
-  personal_data_->AddProfile(profile0);
-
-  // Note: no refresh here.
+  AddProfileToPersonalDataManager(profile0);
 
   // Reset the PersonalDataManager.  This tests that the personal data was saved
   // to the web database, and that we can load the profiles from the web
@@ -1332,10 +1369,8 @@
                        "Orlando", "FL", "32801", "US", "19482937549");
 
   // Add the test profiles to the database.
-  personal_data_->AddProfile(profile0);
-  personal_data_->AddProfile(profile1);
-
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(profile0);
+  AddProfileToPersonalDataManager(profile1);
 
   std::vector<AutofillProfile*> profiles;
   profiles.push_back(&profile0);
@@ -1362,20 +1397,20 @@
   profile_database_service_->RemoveAutofillProfile(profile1.guid());
   profile_database_service_->RemoveAutofillProfile(profile2.guid());
 
-  // Before telling the PDM to refresh, simulate an edit to one of the deleted
-  // profiles via a SetProfile update (this would happen if the Autofill window
-  // was open with a previous snapshot of the profiles, and something
-  // [e.g. sync] removed a profile from the browser.  In this edge case, we will
-  // end up in a consistent state by dropping the write).
-  profile0.SetRawInfo(NAME_FIRST, base::ASCIIToUTF16("Mar"));
-  profile2.SetRawInfo(NAME_FIRST, base::ASCIIToUTF16("Jo"));
-  personal_data_->UpdateProfile(profile0);
-  personal_data_->AddProfile(profile1);
-  personal_data_->AddProfile(profile2);
-
+  personal_data_->Refresh();
   WaitForOnPersonalDataChanged();
 
-  const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
+  auto results = personal_data_->GetProfiles();
+  ASSERT_EQ(1U, results.size());
+  EXPECT_EQ(profile0, *results[0]);
+
+  profile0.SetRawInfo(NAME_FIRST, base::ASCIIToUTF16("Mar"));
+  profile_database_service_->UpdateAutofillProfile(profile0);
+
+  personal_data_->Refresh();
+  WaitForOnPersonalDataChanged();
+
+  results = personal_data_->GetProfiles();
   ASSERT_EQ(1U, results.size());
   EXPECT_EQ(profile0, *results[0]);
 }
@@ -1391,10 +1426,9 @@
   EXPECT_FALSE(profile.IsVerified());
 
   // Add the profile to the database.
-  personal_data_->AddProfile(profile);
+  AddProfileToPersonalDataManager(profile);
 
   // Make sure everything is set up correctly.
-  WaitForOnPersonalDataChanged();
   EXPECT_EQ(1U, personal_data_->GetProfiles().size());
 
   AutofillProfile new_verified_profile = profile;
@@ -1465,10 +1499,9 @@
                        "johnwayne@me.xyz", nullptr, "123 Zoo St.", nullptr,
                        "Hollywood", "CA", "91601", "US", "14155678910");
 
-  personal_data_->AddProfile(profile0);
+  AddProfileToPersonalDataManager(profile0);
 
   // Make sure everything is set up correctly.
-  WaitForOnPersonalDataChanged();
   EXPECT_EQ(1U, personal_data_->GetProfiles().size());
 
   personal_data_->GetNonEmptyTypes(&non_empty_types);
@@ -1500,10 +1533,9 @@
                        "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
                        "Orlando", "FL", "32801", "US", "16502937549");
 
-  personal_data_->AddProfile(profile1);
-  personal_data_->AddProfile(profile2);
+  AddProfileToPersonalDataManager(profile1);
+  AddProfileToPersonalDataManager(profile2);
 
-  WaitForOnPersonalDataChanged();
   EXPECT_EQ(3U, personal_data_->GetProfiles().size());
 
   personal_data_->GetNonEmptyTypes(&non_empty_types);
@@ -1578,7 +1610,7 @@
   test::SetProfileInfo(&steve_jobs, "Steven", "Paul", "Jobs", "sjobs@apple.com",
                        "Apple Computer, Inc.", "1 Infinite Loop", "",
                        "Cupertino", "CA", "95014", "US", "(800) 275-2273");
-  personal_data_->AddProfile(steve_jobs);
+  AddProfileToPersonalDataManager(steve_jobs);
 
   CreditCard bill_gates(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&bill_gates, "William H. Gates", "5555555555554444",
@@ -1655,10 +1687,9 @@
   test::SetProfileInfo(&moose, "Moose", "P", "McMahon", "mpm@example.com", "",
                        "1 Taiga TKTR", "", "Calgary", "AB", "T2B 2K2", "CA",
                        "(800) 555-9000");
-  personal_data_->AddProfile(moose);
+  AddProfileToPersonalDataManager(moose);
 
   // Make sure everything is set up correctly.
-  WaitForOnPersonalDataChanged();
   EXPECT_EQ(1U, personal_data_->GetProfiles().size());
 
   // The value is cached and doesn't change even after adding an address.
@@ -1684,7 +1715,7 @@
   test::SetProfileInfo(&moose, "Moose", "P", "McMahon", "mpm@example.com", "",
                        "1 Taiga TKTR", "", "Calgary", "AB", "T2B 2K2", "CA",
                        "(800) 555-9000");
-  personal_data_->AddProfile(moose);
+  AddProfileToPersonalDataManager(moose);
   ResetPersonalDataManager(USER_MODE_NORMAL);
   EXPECT_EQ("CA", personal_data_->GetDefaultCountryCodeForNewAddress());
 
@@ -1697,38 +1728,27 @@
   test::SetProfileInfo(&armadillo2, "Armin", "Dill", "Oh", "ado@example.com",
                        "", "2 Speed Bump", "", "Lubbock", "TX", "77500", "MX",
                        "(800) 555-9000");
-  personal_data_->AddProfile(armadillo);
-  personal_data_->AddProfile(armadillo2);
+  AddProfileToPersonalDataManager(armadillo);
+  AddProfileToPersonalDataManager(armadillo2);
   ResetPersonalDataManager(USER_MODE_NORMAL);
   EXPECT_EQ("MX", personal_data_->GetDefaultCountryCodeForNewAddress());
 
-  personal_data_->RemoveByGUID(armadillo.guid());
-  personal_data_->RemoveByGUID(armadillo2.guid());
+  RemoveByGUIDFromPersonalDataManager(armadillo.guid());
+  RemoveByGUIDFromPersonalDataManager(armadillo2.guid());
   ResetPersonalDataManager(USER_MODE_NORMAL);
   // Verified profiles count more.
   armadillo.set_origin("http://randomwebsite.com");
   armadillo2.set_origin("http://randomwebsite.com");
-  personal_data_->AddProfile(armadillo);
-  personal_data_->AddProfile(armadillo2);
+  AddProfileToPersonalDataManager(armadillo);
+  AddProfileToPersonalDataManager(armadillo2);
   ResetPersonalDataManager(USER_MODE_NORMAL);
   EXPECT_EQ("CA", personal_data_->GetDefaultCountryCodeForNewAddress());
 
-  personal_data_->RemoveByGUID(armadillo.guid());
+  RemoveByGUIDFromPersonalDataManager(armadillo.guid());
   ResetPersonalDataManager(USER_MODE_NORMAL);
   // But unverified profiles can be a tie breaker.
   armadillo.set_origin(kSettingsOrigin);
-  personal_data_->AddProfile(armadillo);
-  ResetPersonalDataManager(USER_MODE_NORMAL);
-  EXPECT_EQ("MX", personal_data_->GetDefaultCountryCodeForNewAddress());
-
-  // Invalid country codes are ignored.
-  personal_data_->RemoveByGUID(armadillo.guid());
-  personal_data_->RemoveByGUID(moose.guid());
-  AutofillProfile space_invader(base::GenerateGUID(), kSettingsOrigin);
-  test::SetProfileInfo(&space_invader, "Marty", "", "Martian", "mm@example.com",
-                       "", "1 Flying Object", "", "Valles Marineris", "", "",
-                       "XX", "");
-  personal_data_->AddProfile(moose);
+  AddProfileToPersonalDataManager(armadillo);
   ResetPersonalDataManager(USER_MODE_NORMAL);
   EXPECT_EQ("MX", personal_data_->GetDefaultCountryCodeForNewAddress());
 }
@@ -1738,17 +1758,14 @@
   test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
-  personal_data_->AddProfile(profile);
+  AddProfileToPersonalDataManager(profile);
 
   // Make sure everything is set up correctly.
-  WaitForOnPersonalDataChanged();
   EXPECT_EQ(1U, personal_data_->GetProfiles().size());
   EXPECT_EQ(1U, personal_data_->GetProfiles().size());
 
   profile.set_language_code("en");
-  personal_data_->UpdateProfile(profile);
-
-  WaitForOnPersonalDataChanged();
+  UpdateProfileOnPersonalDataManager(profile);
 
   const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
   ASSERT_EQ(1U, results.size());
@@ -1762,7 +1779,7 @@
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
-  personal_data_->AddProfile(profile);
+  AddProfileToPersonalDataManager(profile);
   ResetPersonalDataManager(USER_MODE_NORMAL);
 
   std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions(
@@ -1779,7 +1796,7 @@
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
-  personal_data_->AddProfile(profile);
+  AddProfileToPersonalDataManager(profile);
   ResetPersonalDataManager(USER_MODE_NORMAL);
 
   std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions(
@@ -1813,10 +1830,10 @@
 
   // For easier results verification, make sure |profile| is suggested first.
   profile.set_use_count(5);
-  personal_data_->AddProfile(profile);
-  personal_data_->AddProfile(profile1);
-  personal_data_->AddProfile(profile2);
-  personal_data_->AddProfile(profile3);
+  AddProfileToPersonalDataManager(profile);
+  AddProfileToPersonalDataManager(profile1);
+  AddProfileToPersonalDataManager(profile2);
+  AddProfileToPersonalDataManager(profile3);
   ResetPersonalDataManager(USER_MODE_NORMAL);
 
   // Simulate a form with street address, city and state.
@@ -1842,7 +1859,7 @@
                          "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox",
                          "123 Zoo St.\nSecond Line\nThird line", "unit 5",
                          "Hollywood", "CA", "91601", "US", "12345678910");
-    personal_data_->AddProfile(profile);
+    AddProfileToPersonalDataManager(profile);
     profiles.push_back(profile);
   }
   ResetPersonalDataManager(USER_MODE_NORMAL);
@@ -1876,7 +1893,7 @@
     profile.set_use_count(12);
     profile.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(1));
 
-    personal_data_->AddProfile(profile);
+    AddProfileToPersonalDataManager(profile);
     profiles.push_back(profile);
   }
 
@@ -1888,7 +1905,7 @@
                        "Hollywood", "CA", "91601", "US", "12345678910");
   profile.set_use_count(1);
   profile.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(7));
-  personal_data_->AddProfile(profile);
+  AddProfileToPersonalDataManager(profile);
 
   ResetPersonalDataManager(USER_MODE_NORMAL);
 
@@ -1914,7 +1931,7 @@
                        "Hollywood", "CA", "91601", "US", "12345678910");
   profile3.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(1));
   profile3.set_use_count(5);
-  personal_data_->AddProfile(profile3);
+  AddProfileToPersonalDataManager(profile3);
 
   AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
@@ -1923,7 +1940,7 @@
                        "Hollywood", "CA", "91601", "US", "12345678910");
   profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(1));
   profile1.set_use_count(10);
-  personal_data_->AddProfile(profile1);
+  AddProfileToPersonalDataManager(profile1);
 
   AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
@@ -1932,7 +1949,7 @@
                        "Hollywood", "CA", "91601", "US", "12345678910");
   profile2.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(15));
   profile2.set_use_count(300);
-  personal_data_->AddProfile(profile2);
+  AddProfileToPersonalDataManager(profile2);
 
   ResetPersonalDataManager(USER_MODE_NORMAL);
   std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions(
@@ -1952,21 +1969,21 @@
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
-  personal_data_->AddProfile(profile1);
+  AddProfileToPersonalDataManager(profile1);
 
   AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
-  personal_data_->AddProfile(profile2);
+  AddProfileToPersonalDataManager(profile2);
 
   AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile3, "Marion3", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
-  personal_data_->AddProfile(profile3);
+  AddProfileToPersonalDataManager(profile3);
 
   ResetPersonalDataManager(USER_MODE_NORMAL);
 
@@ -1988,7 +2005,7 @@
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
   profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(200));
-  personal_data_->AddProfile(profile1);
+  AddProfileToPersonalDataManager(profile1);
 
   AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
@@ -1996,7 +2013,7 @@
                        "456 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
   profile2.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(20));
-  personal_data_->AddProfile(profile2);
+  AddProfileToPersonalDataManager(profile2);
 
   ResetPersonalDataManager(USER_MODE_NORMAL);
 
@@ -2072,14 +2089,14 @@
   profile1.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillProfile::INVALID,
                             AutofillProfile::CLIENT);
   profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(20));
-  personal_data_->AddProfile(profile1);
+  AddProfileToPersonalDataManager(profile1);
 
   AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "456 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "1234567890");
-  personal_data_->AddProfile(profile2);
+  AddProfileToPersonalDataManager(profile2);
 
   ResetPersonalDataManager(USER_MODE_NORMAL);
   {
@@ -2139,14 +2156,14 @@
                                              autofill_profile_validity);
   }
   profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(20));
-  personal_data_->AddProfile(profile1);
+  AddProfileToPersonalDataManager(profile1);
 
   AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "456 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "NY", "91601", "US", "1234567890");
-  personal_data_->AddProfile(profile2);
+  AddProfileToPersonalDataManager(profile2);
 
   ResetPersonalDataManager(USER_MODE_NORMAL);
   {
@@ -2194,7 +2211,7 @@
   test::SetProfileInfo(&local_profile, "Josephine", "Alicia", "Saenz",
                        "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
                        "Orlando", "FL", "32801", "US", "19482937549");
-  personal_data_->AddProfile(local_profile);
+  AddProfileToPersonalDataManager(local_profile);
 
   // Add a different server profile.
   std::vector<AutofillProfile> server_profiles;
@@ -2212,6 +2229,7 @@
   prefs::SetProfileAutofillEnabled(personal_data_->pref_service_, false);
   WaitForOnPersonalDataChanged();
   personal_data_->ConvertWalletAddressesAndUpdateWalletCards();
+  WaitForOnPersonalDataChanged();
 
   // Check that profiles were saved.
   EXPECT_EQ(2U, personal_data_->GetProfiles().size());
@@ -2240,7 +2258,7 @@
   test::SetProfileInfo(&local_profile, "Josephine", "Alicia", "Saenz",
                        "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
                        "Orlando", "FL", "32801", "US", "19482937549");
-  personal_data_->AddProfile(local_profile);
+  AddProfileToPersonalDataManager(local_profile);
 
   // Add a different server profile.
   std::vector<AutofillProfile> server_profiles;
@@ -2257,6 +2275,7 @@
   personal_data_->Refresh();
   WaitForOnPersonalDataChanged();
   personal_data_->ConvertWalletAddressesAndUpdateWalletCards();
+  WaitForOnPersonalDataChanged();
 
   // Expect 2 autofilled values or suggestions.
   EXPECT_EQ(2U, personal_data_->GetProfiles().size());
@@ -2288,7 +2307,7 @@
   test::SetProfileInfo(&local_profile, "Josephine", "Alicia", "Saenz",
                        "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
                        "Orlando", "FL", "32801", "US", "19482937549");
-  personal_data_->AddProfile(local_profile);
+  AddProfileToPersonalDataManager(local_profile);
 
   // Expect no profile values or suggestions were added.
   EXPECT_EQ(0U, personal_data_->GetProfiles().size());
@@ -3254,7 +3273,7 @@
   EXPECT_EQ(1U, profile.use_count());
   EXPECT_EQ(kArbitraryTime, profile.use_date());
   EXPECT_EQ(kArbitraryTime, profile.modification_date());
-  personal_data_->AddProfile(profile);
+  AddProfileToPersonalDataManager(profile);
 
   CreditCard credit_card(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card, "John Dillinger",
@@ -3447,7 +3466,7 @@
 
 TEST_F(PersonalDataManagerTest, ClearAllLocalData) {
   // Add some local data.
-  personal_data_->AddProfile(test::GetFullProfile());
+  AddProfileToPersonalDataManager(test::GetFullProfile());
   personal_data_->AddCreditCard(test::GetCreditCard());
   personal_data_->Refresh();
 
@@ -3529,6 +3548,7 @@
   }
 
   personal_data_->SaveImportedProfile(profile2);
+  WaitForOnPersonalDataChanged();
 
   const std::vector<AutofillProfile*>& saved_profiles =
       personal_data_->GetProfiles();
@@ -4225,12 +4245,12 @@
   // Associate the third card with profile6.
   credit_card3.set_billing_address_id(profile6.guid());
 
-  personal_data_->AddProfile(profile1);
-  personal_data_->AddProfile(profile2);
-  personal_data_->AddProfile(profile3);
-  personal_data_->AddProfile(profile4);
-  personal_data_->AddProfile(profile5);
-  personal_data_->AddProfile(profile6);
+  AddProfileToPersonalDataManager(profile1);
+  AddProfileToPersonalDataManager(profile2);
+  AddProfileToPersonalDataManager(profile3);
+  AddProfileToPersonalDataManager(profile4);
+  AddProfileToPersonalDataManager(profile5);
+  AddProfileToPersonalDataManager(profile6);
   personal_data_->AddCreditCard(credit_card1);
   personal_data_->AddCreditCard(credit_card2);
   personal_data_->AddCreditCard(credit_card3);
@@ -4304,11 +4324,9 @@
   profile3.set_use_count(3);
   profile3.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(5));
 
-  personal_data_->AddProfile(profile1);
-  personal_data_->AddProfile(profile2);
-  personal_data_->AddProfile(profile3);
-
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(profile1);
+  AddProfileToPersonalDataManager(profile2);
+  AddProfileToPersonalDataManager(profile3);
 
   // Make sure the 3 profiles were saved;
   EXPECT_EQ(3U, personal_data_->GetProfiles().size());
@@ -4394,11 +4412,9 @@
   profile3.set_use_count(3);
   profile3.set_use_date(kArbitraryTime);
 
-  personal_data_->AddProfile(profile1);
-  personal_data_->AddProfile(profile2);
-  personal_data_->AddProfile(profile3);
-
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(profile1);
+  AddProfileToPersonalDataManager(profile2);
+  AddProfileToPersonalDataManager(profile3);
 
   // Make sure the 3 profiles were saved.
   EXPECT_EQ(3U, personal_data_->GetProfiles().size());
@@ -4460,11 +4476,9 @@
   profile3.set_use_count(3);
   profile3.set_use_date(kArbitraryTime);
 
-  personal_data_->AddProfile(profile1);
-  personal_data_->AddProfile(profile2);
-  personal_data_->AddProfile(profile3);
-
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(profile1);
+  AddProfileToPersonalDataManager(profile2);
+  AddProfileToPersonalDataManager(profile3);
 
   // Make sure the 3 profiles were saved.
   EXPECT_EQ(3U, personal_data_->GetProfiles().size());
@@ -4525,11 +4539,9 @@
   profile3.set_use_count(3);
   profile3.set_use_date(kArbitraryTime);
 
-  personal_data_->AddProfile(profile1);
-  personal_data_->AddProfile(profile2);
-  personal_data_->AddProfile(profile3);
-
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(profile1);
+  AddProfileToPersonalDataManager(profile2);
+  AddProfileToPersonalDataManager(profile3);
 
   // Make sure the 3 profiles were saved.
   EXPECT_EQ(3U, personal_data_->GetProfiles().size());
@@ -4637,15 +4649,13 @@
   Barney.set_use_count(1);
   Barney.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(180));
 
-  personal_data_->AddProfile(Homer1);
-  personal_data_->AddProfile(Homer2);
-  personal_data_->AddProfile(Homer3);
-  personal_data_->AddProfile(Homer4);
-  personal_data_->AddProfile(Marge1);
-  personal_data_->AddProfile(Marge2);
-  personal_data_->AddProfile(Barney);
-
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(Homer1);
+  AddProfileToPersonalDataManager(Homer2);
+  AddProfileToPersonalDataManager(Homer3);
+  AddProfileToPersonalDataManager(Homer4);
+  AddProfileToPersonalDataManager(Marge1);
+  AddProfileToPersonalDataManager(Marge2);
+  AddProfileToPersonalDataManager(Barney);
 
   // Make sure the 7 profiles were saved;
   EXPECT_EQ(7U, personal_data_->GetProfiles().size());
@@ -4728,10 +4738,8 @@
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "", "");
 
-  personal_data_->AddProfile(profile1);
-  personal_data_->AddProfile(profile2);
-
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(profile1);
+  AddProfileToPersonalDataManager(profile2);
 
   // Make sure both profiles were saved.
   EXPECT_EQ(2U, personal_data_->GetProfiles().size());
@@ -4756,9 +4764,8 @@
                        "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "");
 
-  personal_data_->AddProfile(profile);
+  AddProfileToPersonalDataManager(profile);
 
-  WaitForOnPersonalDataChanged();
   EXPECT_EQ(1U, personal_data_->GetProfiles().size());
 
   // Enable the profile cleanup now. Otherwise it would be triggered by the
@@ -4782,10 +4789,9 @@
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "", "");
 
-  personal_data_->AddProfile(profile1);
-  personal_data_->AddProfile(profile2);
+  AddProfileToPersonalDataManager(profile1);
+  AddProfileToPersonalDataManager(profile2);
 
-  WaitForOnPersonalDataChanged();
   EXPECT_EQ(2U, personal_data_->GetProfiles().size());
 
   // Enable the profile cleanup now. Otherwise it would be triggered by the
@@ -4807,8 +4813,7 @@
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "", "");
 
-  personal_data_->AddProfile(profile3);
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(profile3);
 
   // Make sure |profile3| was saved.
   EXPECT_EQ(2U, personal_data_->GetProfiles().size());
@@ -4857,7 +4862,7 @@
                        "1234 Evergreen Terrace", "Bld. 6", "Springfield", "IL",
                        "32801", "US", "15151231234");
   profile0.set_use_date(now - base::TimeDelta::FromDays(400));
-  personal_data_->AddProfile(profile0);
+  AddProfileToPersonalDataManager(profile0);
 
   // Create unverified/disused/used-by-expired-credit-card address(deletable).
   AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
@@ -4871,9 +4876,9 @@
                           "1");
   credit_card0.set_use_date(now - base::TimeDelta::FromDays(400));
   credit_card0.set_billing_address_id(profile1.guid());
-  personal_data_->AddProfile(profile1);
+  AddProfileToPersonalDataManager(profile1);
   personal_data_->AddCreditCard(credit_card0);
-
+  WaitForOnPersonalDataChanged();
   // Create verified/disused/not-used-by-valid-credit-card address(not
   // deletable).
   AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
@@ -4882,7 +4887,7 @@
                        "32801", "US", "15151231234");
   profile2.set_origin(kSettingsOrigin);
   profile2.set_use_date(now - base::TimeDelta::FromDays(400));
-  personal_data_->AddProfile(profile2);
+  AddProfileToPersonalDataManager(profile2);
 
   // Create unverified/recently-used/not-used-by-valid-credit-card address(not
   // deletable).
@@ -4891,7 +4896,7 @@
                        "1234 Evergreen Terrace", "Bld. 9", "Springfield", "IL",
                        "32801", "US", "15151231234");
   profile3.set_use_date(now - base::TimeDelta::FromDays(4));
-  personal_data_->AddProfile(profile3);
+  AddProfileToPersonalDataManager(profile3);
 
   // Create unverified/disused/used-by-valid-credit-card address(not deletable).
   AutofillProfile profile4(base::GenerateGUID(), test::kEmptyOrigin);
@@ -4904,7 +4909,7 @@
   credit_card1.SetNetworkForMaskedCard(kVisaCard);
   credit_card1.set_billing_address_id(profile4.guid());
   credit_card1.set_use_date(now - base::TimeDelta::FromDays(1));
-  personal_data_->AddProfile(profile4);
+  AddProfileToPersonalDataManager(profile4);
   personal_data_->AddCreditCard(credit_card1);
 
   WaitForOnPersonalDataChanged();
@@ -5101,7 +5106,7 @@
                        "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
                        "Orlando", "FL", "32801", "US", "19482937549");
   local_profile.set_use_count(1);
-  personal_data_->AddProfile(local_profile);
+  AddProfileToPersonalDataManager(local_profile);
 
   // Add a different server profile.
   std::vector<AutofillProfile> server_profiles;
@@ -5207,7 +5212,7 @@
                        "1212 Center.", "Bld. 5", "Orlando", "FL", "32801", "US",
                        "19482937549");
   local_profile.set_use_count(1);
-  personal_data_->AddProfile(local_profile);
+  AddProfileToPersonalDataManager(local_profile);
 
   // Add a different server profile.
   std::vector<AutofillProfile> server_profiles;
@@ -5364,7 +5369,7 @@
                        "1212 Center.", "Bld. 5", "Orlando", "FL", "32801", "US",
                        "19482937549");
   local_profile.set_use_count(1);
-  personal_data_->AddProfile(local_profile);
+  AddProfileToPersonalDataManager(local_profile);
 
   // Add a server profile.
   std::vector<AutofillProfile> server_profiles;
@@ -5587,7 +5592,7 @@
   AutofillProfile local_profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&local_profile, "Josephine", "Alicia", "Saenz", "",
                        "Fox", "1212 Center.", "Bld. 5", "", "", "", "", "");
-  personal_data_->AddProfile(local_profile);
+  AddProfileToPersonalDataManager(local_profile);
 
   // Add two server profiles: The first is unique, the second is similar to the
   // local one but has some additional info.
@@ -5680,8 +5685,8 @@
   server_cards.push_back(server_card1);
 
   // Add the data to the database.
-  personal_data_->AddProfile(profile0);
-  personal_data_->AddProfile(profile1);
+  AddProfileToPersonalDataManager(profile0);
+  AddProfileToPersonalDataManager(profile1);
   personal_data_->AddCreditCard(local_card0);
   personal_data_->AddCreditCard(local_card1);
   SetServerCards(server_cards);
@@ -5697,14 +5702,14 @@
   ///////////////////////////////////////////////////////////////////////
   // Tested method.
   ///////////////////////////////////////////////////////////////////////
-  personal_data_->RemoveByGUID(profile0.guid());
+  RemoveByGUIDFromPersonalDataManager(profile0.guid());
 
   ///////////////////////////////////////////////////////////////////////
   // Validation.
   ///////////////////////////////////////////////////////////////////////
 
   // Wait for the data to be refreshed.
-  WaitForOnPersonalDataChanged();
+  // WaitForOnPersonalDataChanged();
 
   // Make sure only profile0 was deleted.
   ASSERT_EQ(1U, personal_data_->GetProfiles().size());
@@ -5742,7 +5747,7 @@
   test::SetProfileInfo(&profile0, "Bob", "", "Doe", "", "Fox", "1212 Center.",
                        "Bld. 5", "Orlando", "FL", "32801", "US", "19482937549");
   profile0.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(3));
-  personal_data_->AddProfile(profile0);
+  AddProfileToPersonalDataManager(profile0);
 
   // Add a profile used a long time (200 days) ago.
   AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
@@ -5750,7 +5755,7 @@
                        "1234 Evergreen Terrace", "Bld. 5", "Springfield", "IL",
                        "32801", "US", "15151231234");
   profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(200));
-  personal_data_->AddProfile(profile1);
+  AddProfileToPersonalDataManager(profile1);
 
   // Reload the database, which will log the stored profile counts.
   base::HistogramTester histogram_tester;
@@ -6024,6 +6029,8 @@
 
   // Reloading the test profile should result in test data being created.
   ResetPersonalDataManager(USER_MODE_NORMAL);
+  WaitOnceForOnPersonalDataChanged();
+
   const std::vector<AutofillProfile*> addresses = personal_data_->GetProfiles();
   const std::vector<CreditCard*> credit_cards =
       personal_data_->GetCreditCards();
@@ -6359,7 +6366,7 @@
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
   profile0.set_use_count(10000);
-  personal_data_->AddProfile(profile0);
+  AddProfileToPersonalDataManager(profile0);
 
   AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
@@ -6367,7 +6374,7 @@
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
   profile1.set_use_count(1000);
-  personal_data_->AddProfile(profile1);
+  AddProfileToPersonalDataManager(profile1);
 
   AutofillProfile profile2(base::GenerateGUID(), "1234");
   test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
@@ -6375,7 +6382,7 @@
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
   profile2.set_use_count(100);
-  personal_data_->AddProfile(profile2);
+  AddProfileToPersonalDataManager(profile2);
 
   // Create a profile with a settings origin.
   AutofillProfile profile3(base::GenerateGUID(), kSettingsOrigin);
@@ -6384,9 +6391,8 @@
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
   profile3.set_use_count(10);
-  personal_data_->AddProfile(profile3);
+  AddProfileToPersonalDataManager(profile3);
 
-  WaitForOnPersonalDataChanged();
   ASSERT_EQ(4U, personal_data_->GetProfiles().size());
 
   personal_data_->ClearProfileNonSettingsOrigins();
@@ -6466,7 +6472,7 @@
     test::SetProfileInfo(&profile0, "Homer", "J", "Simpson",
                          "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                          "", "Springfield", "IL", "91601", "US", "");
-    personal_data_->AddProfile(profile0);
+    AddProfileToPersonalDataManager(profile0);
   }
 
   // A JP profile with both street address and a city.
@@ -6476,7 +6482,7 @@
     test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
                          "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                          "", "Springfield", "IL", "91601", "JP", "");
-    personal_data_->AddProfile(profile1);
+    AddProfileToPersonalDataManager(profile1);
   }
 
   // A JP profile with only a city.
@@ -6486,7 +6492,7 @@
     test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
                          "homer.simpson@abc.com", "", "", "", "Springfield",
                          "IL", "91601", "JP", "");
-    personal_data_->AddProfile(profile2);
+    AddProfileToPersonalDataManager(profile2);
   }
 
   // A JP profile with only a street address.
@@ -6496,7 +6502,7 @@
     test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
                          "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                          "", "", "IL", "91601", "JP", "");
-    personal_data_->AddProfile(profile3);
+    AddProfileToPersonalDataManager(profile3);
   }
 
   // A JP profile with neither a street address nor a city.
@@ -6506,11 +6512,9 @@
     test::SetProfileInfo(&profile4, "Homer", "J", "Simpson",
                          "homer.simpson@abc.com", "", "", "", "", "IL", "91601",
                          "JP", "");
-    personal_data_->AddProfile(profile4);
+    AddProfileToPersonalDataManager(profile4);
   }
 
-  WaitForOnPersonalDataChanged();
-
   personal_data_->MoveJapanCityToStreetAddress();
 
   WaitForOnPersonalDataChanged();
@@ -6566,8 +6570,7 @@
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
-  personal_data_->AddProfile(profile);
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(profile);
 
   // Turn off autofill profile sync.
   auto model_type_set = sync_service_.GetActiveDataTypes();
@@ -6726,9 +6729,7 @@
   test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox", "123 Zoo St", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
-  personal_data_->AddProfile(profile);
-
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(profile);
 
   std::vector<std::unique_ptr<AutofillProfile>> profiles;
   // Expect that a profile is stored in the profile autofill table.
@@ -6822,7 +6823,7 @@
   // Create three profiles and add them to personal_data_.
   AutofillProfile valid_profile(test::GetFullValidProfileForCanada());
   valid_profile.set_guid("00000000-0000-0000-0000-000000000001");
-  personal_data_->AddProfile(valid_profile);
+  AddProfileToPersonalDataManager(valid_profile);
 
   AutofillProfile profile_invalid_phone_email(
       test::GetFullValidProfileForChina());
@@ -6831,7 +6832,7 @@
   profile_invalid_phone_email.SetRawInfo(EMAIL_ADDRESS,
                                          base::UTF8ToUTF16("invalid email!"));
   profile_invalid_phone_email.set_guid("00000000-0000-0000-0000-000000000002");
-  personal_data_->AddProfile(profile_invalid_phone_email);
+  AddProfileToPersonalDataManager(profile_invalid_phone_email);
 
   AutofillProfile profile_invalid_province(base::GenerateGUID(),
                                            test::kEmptyOrigin);
@@ -6839,9 +6840,8 @@
                        "alice@munro.ca", "Fox", "123 Zoo St", "unit 5",
                        "Montreal", "CA", "H3C 2A3", "CA", "15142343254");
   profile_invalid_province.set_guid("00000000-0000-0000-0000-000000000003");
-  personal_data_->AddProfile(profile_invalid_province);
+  AddProfileToPersonalDataManager(profile_invalid_province);
 
-  WaitForOnPersonalDataChanged();
   ASSERT_EQ(3U, personal_data_->GetProfiles().size());
 
   // Validate the profiles through the client validation API.
@@ -6935,12 +6935,11 @@
 TEST_F(PersonalDataManagerTest, UpdateClientValidityStates_UpdatedFlag) {
   // Create two profiles and add them to personal_data_.
   AutofillProfile profile1(test::GetFullValidProfileForCanada());
-  personal_data_->AddProfile(profile1);
+  AddProfileToPersonalDataManager(profile1);
 
   AutofillProfile profile2(test::GetFullValidProfileForChina());
-  personal_data_->AddProfile(profile2);
+  AddProfileToPersonalDataManager(profile2);
 
-  WaitForOnPersonalDataChanged();
   ASSERT_EQ(2U, personal_data_->GetProfiles().size());
 
   // Validate the profiles through the client validation API.
@@ -6983,13 +6982,11 @@
   // Create two profiles and add them to personal_data_.
   AutofillProfile profile1(test::GetFullValidProfileForCanada());
   profile1.SetRawInfo(EMAIL_ADDRESS, base::UTF8ToUTF16("invalid email!"));
-  personal_data_->AddProfile(profile1);
+  AddProfileToPersonalDataManager(profile1);
 
   AutofillProfile profile2(test::GetFullValidProfileForChina());
   profile2.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("invalid state!"));
-  personal_data_->AddProfile(profile2);
-
-  WaitForOnPersonalDataChanged();
+  AddProfileToPersonalDataManager(profile2);
 
   EXPECT_CALL(*personal_data_, OnValidated(testing::_)).Times(0);
 
@@ -7026,14 +7023,13 @@
   AutofillProfile profile1(test::GetFullValidProfileForCanada());
   profile1.SetRawInfo(EMAIL_ADDRESS, base::UTF8ToUTF16("invalid email!"));
   profile1.set_guid("00000000-0000-0000-0000-000000000001");
-  personal_data_->AddProfile(profile1);
+  AddProfileToPersonalDataManager(profile1);
 
   AutofillProfile profile2(test::GetFullValidProfileForChina());
   profile2.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("invalid state!"));
   profile2.set_guid("00000000-0000-0000-0000-000000000002");
-  personal_data_->AddProfile(profile2);
+  AddProfileToPersonalDataManager(profile2);
 
-  WaitForOnPersonalDataChanged();
   auto profiles = personal_data_->GetProfiles();
 
   // Pretend that the validity states are updated.
diff --git a/components/autofill/core/browser/webdata/autofill_change.h b/components/autofill/core/browser/webdata/autofill_change.h
index af764ed..600692e 100644
--- a/components/autofill/core/browser/webdata/autofill_change.h
+++ b/components/autofill/core/browser/webdata/autofill_change.h
@@ -9,11 +9,11 @@
 #include <vector>
 
 #include "base/logging.h"
+#include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/webdata/autofill_entry.h"
 
 namespace autofill {
 
-class AutofillProfile;
 class CreditCard;
 
 // For classic Autofill form fields, the KeyType is AutofillKey.
@@ -88,6 +88,25 @@
 typedef AutofillDataModelChange<AutofillProfile> AutofillProfileChange;
 typedef AutofillDataModelChange<CreditCard> CreditCardChange;
 
+class AutofillProfileDeepChange : public AutofillProfileChange {
+ public:
+  AutofillProfileDeepChange(Type type, const AutofillProfile& profile)
+      : AutofillProfileChange(type, profile.guid(), &profile),
+        profile_(profile) {}
+
+  AutofillProfileDeepChange(Type type, const std::string& guid)
+      : AutofillProfileChange(type, guid, nullptr), profile_(guid, "") {
+    DCHECK(type == GenericAutofillChange::REMOVE);
+  }
+
+  ~AutofillProfileDeepChange() override {}
+
+  AutofillProfile profile() const { return profile_; }
+
+ private:
+  AutofillProfile profile_;
+};
+
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_CHANGE_H__
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
index 3c4deea..edc03da 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
+++ b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
@@ -15,6 +15,7 @@
 #include "components/autofill/core/browser/webdata/autofill_change.h"
 #include "components/autofill/core/browser/webdata/autofill_entry.h"
 #include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "components/webdata/common/web_database_backend.h"
@@ -53,6 +54,11 @@
   DCHECK(!user_data_);  // Forgot to call ResetUserData?
 }
 
+void AutofillWebDataBackendImpl::SetAutofillProfileChangedCallback(
+    base::RepeatingCallback<void(const AutofillProfileDeepChange&)> change_cb) {
+  on_autofill_profile_changed_cb_ = std::move(change_cb);
+}
+
 WebDatabase* AutofillWebDataBackendImpl::GetDatabase() {
   DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
   return web_database_backend_->database();
@@ -202,6 +208,13 @@
   for (auto& db_observer : db_observer_list_)
     db_observer.AutofillProfileChanged(change);
 
+  if (!on_autofill_profile_changed_cb_.is_null()) {
+    ui_task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(on_autofill_profile_changed_cb_,
+                                  AutofillProfileDeepChange(
+                                      AutofillProfileChange::ADD, profile)));
+  }
+
   return WebDatabase::COMMIT_NEEDED;
 }
 
@@ -227,6 +240,13 @@
   for (auto& db_observer : db_observer_list_)
     db_observer.AutofillProfileChanged(change);
 
+  if (!on_autofill_profile_changed_cb_.is_null()) {
+    ui_task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(on_autofill_profile_changed_cb_,
+                                  AutofillProfileDeepChange(
+                                      AutofillProfileChange::UPDATE, profile)));
+  }
+
   return WebDatabase::COMMIT_NEEDED;
 }
 
@@ -250,6 +270,13 @@
   for (auto& db_observer : db_observer_list_)
     db_observer.AutofillProfileChanged(change);
 
+  if (!on_autofill_profile_changed_cb_.is_null()) {
+    ui_task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(on_autofill_profile_changed_cb_,
+                                  AutofillProfileDeepChange(
+                                      AutofillProfileChange::REMOVE, guid)));
+  }
+
   return WebDatabase::COMMIT_NEEDED;
 }
 
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h
index 064d7ec..41b5861 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h
+++ b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h
@@ -55,6 +55,10 @@
       const base::Closure& on_changed_callback,
       const base::Callback<void(syncer::ModelType)>& on_sync_started_callback);
 
+  void SetAutofillProfileChangedCallback(
+      base::RepeatingCallback<void(const AutofillProfileDeepChange&)>
+          change_cb);
+
   // AutofillWebDataBackend implementation.
   void AddObserver(
       AutofillWebDataServiceObserverOnDBSequence* observer) override;
@@ -230,6 +234,9 @@
   base::Closure on_changed_callback_;
   base::Callback<void(syncer::ModelType)> on_sync_started_callback_;
 
+  base::RepeatingCallback<void(const AutofillProfileDeepChange&)>
+      on_autofill_profile_changed_cb_;
+
   DISALLOW_COPY_AND_ASSIGN(AutofillWebDataBackendImpl);
 };
 
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_service.cc b/components/autofill/core/browser/webdata/autofill_webdata_service.cc
index dd40364..2e4bda52 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_service.cc
+++ b/components/autofill/core/browser/webdata/autofill_webdata_service.cc
@@ -107,6 +107,11 @@
            autofill_backend_, profile));
 }
 
+void AutofillWebDataService::SetAutofillProfileChangedCallback(
+    base::RepeatingCallback<void(const AutofillProfileDeepChange&)> change_cb) {
+  autofill_backend_->SetAutofillProfileChangedCallback(std::move(change_cb));
+}
+
 void AutofillWebDataService::UpdateAutofillProfile(
     const AutofillProfile& profile) {
   wdbs_->ScheduleDBTask(FROM_HERE,
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_service.h b/components/autofill/core/browser/webdata/autofill_webdata_service.h
index a1db37c..c40ad6108 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_service.h
+++ b/components/autofill/core/browser/webdata/autofill_webdata_service.h
@@ -12,6 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/supports_user_data.h"
+#include "components/autofill/core/browser/webdata/autofill_change.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "components/sync/base/model_type.h"
@@ -83,6 +84,10 @@
   void UpdateAutofillEntries(
       const std::vector<AutofillEntry>& autofill_entries) override;
 
+  void SetAutofillProfileChangedCallback(
+      base::RepeatingCallback<void(const AutofillProfileDeepChange&)>
+          change_cb);
+
   // Credit cards.
   void AddCreditCard(const CreditCard& credit_card) override;
   void UpdateCreditCard(const CreditCard& credit_card) override;
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h b/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
index 94805a9..7477ce7 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
+++ b/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
@@ -37,6 +37,8 @@
   // Sync.
   virtual void AutofillMultipleChanged() {}
 
+  virtual void AutofillProfileChanged(const AutofillProfileChange& change) {}
+
   // Called on UI sequence when sync has started for |model_type|.
   virtual void SyncStarted(syncer::ModelType /* model_type */) {}
 
diff --git a/components/autofill/core/common/save_password_progress_logger.cc b/components/autofill/core/common/save_password_progress_logger.cc
index 57c49b8..3c18633 100644
--- a/components/autofill/core/common/save_password_progress_logger.cc
+++ b/components/autofill/core/common/save_password_progress_logger.cc
@@ -305,7 +305,7 @@
     case SavePasswordProgressLogger::STRING_ON_ASK_USER_OR_SAVE_PASSWORD:
       return "PasswordManager::AskUserOrSavePassword";
     case SavePasswordProgressLogger::STRING_CAN_PROVISIONAL_MANAGER_SAVE_METHOD:
-      return "PasswordManager::IsReadyForAutomaticSaving";
+      return "PasswordManager::IsAutomaticSavePromptAvailable";
     case SavePasswordProgressLogger::STRING_NO_PROVISIONAL_SAVE_MANAGER:
       return "No provisional save manager";
     case SavePasswordProgressLogger::STRING_NUMBER_OF_VISIBLE_FORMS:
diff --git a/components/dom_distiller/content/browser/web_contents_main_frame_observer_unittest.cc b/components/dom_distiller/content/browser/web_contents_main_frame_observer_unittest.cc
index 2d76ff7..964eedf2 100644
--- a/components/dom_distiller/content/browser/web_contents_main_frame_observer_unittest.cc
+++ b/components/dom_distiller/content/browser/web_contents_main_frame_observer_unittest.cc
@@ -4,11 +4,11 @@
 
 #include "components/dom_distiller/content/browser/web_contents_main_frame_observer.h"
 
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/test_renderer_host.h"
 
 namespace dom_distiller {
@@ -34,10 +34,10 @@
         content::RenderFrameHostTester::For(rfh);
     if (!main_frame)
       rfh = rfh_tester->AppendChild("subframe");
-    std::unique_ptr<content::NavigationHandle> navigation_handle =
-        content::NavigationHandle::CreateNavigationHandleForTesting(
-            GURL(), rfh, true, net::OK, same_document);
-    // Destructor calls DidFinishNavigation.
+    content::MockNavigationHandle navigation_handle(GURL(), rfh);
+    navigation_handle.set_has_committed(true);
+    navigation_handle.set_is_same_document(same_document);
+    main_frame_observer_->DidFinishNavigation(&navigation_handle);
   }
 
  protected:
diff --git a/components/download/internal/common/resource_downloader.cc b/components/download/internal/common/resource_downloader.cc
index ec7b6a1..751474f 100644
--- a/components/download/internal/common/resource_downloader.cc
+++ b/components/download/internal/common/resource_downloader.cc
@@ -225,7 +225,9 @@
 }
 
 void ResourceDownloader::OnReceiveRedirect() {
-  url_loader_->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+  url_loader_->FollowRedirect(std::vector<std::string>() /* removed_headers */,
+                              net::HttpRequestHeaders() /* modified_headers */,
+                              base::nullopt);
 }
 
 void ResourceDownloader::OnResponseCompleted() {
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index 8717ee37..08b4298 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -653,7 +653,7 @@
 
   ProvisionallySavePassword(password_form, driver);
 
-  if (IsReadyForAutomaticSaving())
+  if (IsAutomaticSavePromptAvailable())
     OnLoginSuccessful();
 }
 
@@ -957,7 +957,7 @@
   provisional_save_manager_.swap(manager);
 }
 
-bool PasswordManager::IsReadyForAutomaticSaving() {
+bool PasswordManager::IsAutomaticSavePromptAvailable() {
   std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
   if (password_manager_util::IsLoggingActive(client_)) {
     logger.reset(
@@ -1008,7 +1008,7 @@
     logger->LogMessage(Logger::STRING_ON_PASSWORD_FORMS_RENDERED_METHOD);
   }
 
-  if (!IsReadyForAutomaticSaving())
+  if (!IsAutomaticSavePromptAvailable())
     return;
 
   PasswordFormManagerInterface* submitted_manager = GetSubmittedManager();
diff --git a/components/password_manager/core/browser/password_manager.h b/components/password_manager/core/browser/password_manager.h
index e5bc56d..ac62ebc8 100644
--- a/components/password_manager/core/browser/password_manager.h
+++ b/components/password_manager/core/browser/password_manager.h
@@ -198,9 +198,10 @@
                                 PasswordFormManager* matched_manager,
                                 BrowserSavePasswordProgressLogger* logger);
 
-  // Returns true if |provisional_save_manager_| is ready for saving and
-  // non-blacklisted.
-  bool IsReadyForAutomaticSaving();
+  // Returns true if there is a form manager for a submitted form and this form
+  // manager contains the submitted credentials suitable for automatic save
+  // prompt, not for manual fallback only.
+  bool IsAutomaticSavePromptAvailable();
 
   // Returns true if there already exists a provisionally saved password form
   // from the same origin as |form|, but with a different and secure scheme.
diff --git a/components/policy/core/common/cloud/policy_header_service.cc b/components/policy/core/common/cloud/policy_header_service.cc
index e4a38448..6b7bf02 100644
--- a/components/policy/core/common/cloud/policy_header_service.cc
+++ b/components/policy/core/common/cloud/policy_header_service.cc
@@ -37,14 +37,12 @@
 
 void PolicyHeaderService::AddPolicyHeaders(
     const GURL& url,
-    std::unique_ptr<net::HttpRequestHeaders>* extra_headers) const {
-  DCHECK(extra_headers);
-  if (!policy_header_.empty() &&
-      url.spec().compare(0, server_url_.size(), server_url_) == 0) {
-    if (!extra_headers->get())
-      (*extra_headers) = std::make_unique<net::HttpRequestHeaders>();
-    (*extra_headers)->SetHeader(kChromePolicyHeader, policy_header_);
-  }
+    net::HttpRequestHeaders* extra_headers) const {
+  if (policy_header_.empty())
+    return;
+  if (url.spec().compare(0, server_url_.size(), server_url_) != 0)
+    return;
+  extra_headers->SetHeader(kChromePolicyHeader, policy_header_);
 }
 
 std::string PolicyHeaderService::CreateHeaderValue() {
diff --git a/components/policy/core/common/cloud/policy_header_service.h b/components/policy/core/common/cloud/policy_header_service.h
index 584fa5d..327daa92 100644
--- a/components/policy/core/common/cloud/policy_header_service.h
+++ b/components/policy/core/common/cloud/policy_header_service.h
@@ -33,11 +33,10 @@
                       CloudPolicyStore* user_policy_store);
   ~PolicyHeaderService() override;
 
-  // Update |*extra_headers| (allocate if necessary) with the policy header if
-  // |url| matches |server_url_|. Otherwise |extra_headers| remains unchanged.
-  void AddPolicyHeaders(
-      const GURL& url,
-      std::unique_ptr<net::HttpRequestHeaders>* extra_headers) const;
+  // Update |*extra_headers| with the policy header if
+  // |url| matches |server_url_|. Otherwise |*extra_headers| remains unchanged.
+  void AddPolicyHeaders(const GURL& url,
+                        net::HttpRequestHeaders* extra_headers) const;
 
   // Overridden CloudPolicyStore::Observer methods:
   void OnStoreLoaded(CloudPolicyStore* store) override;
diff --git a/components/policy/core/common/cloud/policy_header_service_unittest.cc b/components/policy/core/common/cloud/policy_header_service_unittest.cc
index d6196ee4..b66063eb 100644
--- a/components/policy/core/common/cloud/policy_header_service_unittest.cc
+++ b/components/policy/core/common/cloud/policy_header_service_unittest.cc
@@ -110,44 +110,39 @@
   user_store_.SetPolicy(std::move(policy));
   task_runner_->RunUntilIdle();
 
-  std::unique_ptr<net::HttpRequestHeaders> extra_headers =
-      std::make_unique<net::HttpRequestHeaders>();
+  net::HttpRequestHeaders extra_headers;
   service_->AddPolicyHeaders(GURL(kDMServerURL), &extra_headers);
-  ValidateHeader(*extra_headers, expected_dmtoken, expected_policy_token);
+  ValidateHeader(extra_headers, expected_dmtoken, expected_policy_token);
 
   // Now blow away the policy data.
   user_store_.SetPolicy(std::unique_ptr<PolicyData>());
   task_runner_->RunUntilIdle();
 
-  std::unique_ptr<net::HttpRequestHeaders> extra_headers2 =
-      std::make_unique<net::HttpRequestHeaders>();
+  net::HttpRequestHeaders extra_headers2;
   service_->AddPolicyHeaders(GURL(kDMServerURL), &extra_headers2);
-  ValidateHeader(*extra_headers2, "", "");
+  ValidateHeader(extra_headers2, "", "");
 }
 
 TEST_F(PolicyHeaderServiceTest, NoHeaderOnNonMatchingURL) {
   service_->SetHeaderForTest("new_header");
-  std::unique_ptr<net::HttpRequestHeaders> extra_headers =
-      std::make_unique<net::HttpRequestHeaders>();
+  net::HttpRequestHeaders extra_headers;
   service_->AddPolicyHeaders(GURL("http://non-matching.com"), &extra_headers);
-  EXPECT_TRUE(extra_headers->IsEmpty());
+  EXPECT_TRUE(extra_headers.IsEmpty());
 }
 
 TEST_F(PolicyHeaderServiceTest, HeaderChange) {
   std::string new_header = "new_header";
   service_->SetHeaderForTest(new_header);
-  std::unique_ptr<net::HttpRequestHeaders> extra_headers =
-      std::make_unique<net::HttpRequestHeaders>();
+  net::HttpRequestHeaders extra_headers;
   service_->AddPolicyHeaders(GURL(kDMServerURL), &extra_headers);
-  ValidateHeader(*extra_headers, new_header);
+  ValidateHeader(extra_headers, new_header);
 }
 
 TEST_F(PolicyHeaderServiceTest, ChangeToNoHeader) {
   service_->SetHeaderForTest("");
-  std::unique_ptr<net::HttpRequestHeaders> extra_headers =
-      std::make_unique<net::HttpRequestHeaders>();
+  net::HttpRequestHeaders extra_headers;
   service_->AddPolicyHeaders(GURL(kDMServerURL), &extra_headers);
-  EXPECT_TRUE(extra_headers->IsEmpty());
+  EXPECT_TRUE(extra_headers.IsEmpty());
 }
 
 }  // namespace policy
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index a643d48..4385b3c 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -12563,7 +12563,9 @@
       'desc': '''
         If this policy is set to True, cloud management enrollment is mandatory and blocks Chrome launch process if failed.
 
-        If this policy is left unset or set to False, cloud management enrollment is optional and does not blocks Chrome launch process if failed.''',
+        If this policy is left unset or set to False, cloud management enrollment is optional and does not blocks Chrome launch process if failed.
+
+        This policy is used by machine scope cloud policy enrollment on desktop and can be set by Registry or GPO on Windows, plist on Mac and JSON policy file on Linux.''',
     },
     {
       'name': 'AutoplayAllowed',
diff --git a/components/policy/tools/syntax_check_policy_template_json.py b/components/policy/tools/syntax_check_policy_template_json.py
index 8ee6ac41..5ddb145e 100755
--- a/components/policy/tools/syntax_check_policy_template_json.py
+++ b/components/policy/tools/syntax_check_policy_template_json.py
@@ -285,8 +285,19 @@
     # Each policy must have a caption message.
     self._CheckContains(policy, 'caption', str)
 
-    # Each policy must have a description message.
-    self._CheckContains(policy, 'desc', str)
+    # Each policy must have a description message shorter than 4096 characters
+    # in all its translations (ADM format limitation).
+    desc = self._CheckContains(policy, 'desc', str)
+    if len(desc.decode("UTF-8")) > 4096:
+      self._Error(
+          'The length of the description is more than the limit of 4096'
+          ' characters long', 'policy', policy.get('name'))
+    # Warning length picked right above the largest existing policy.
+    elif len(desc.decode("UTF-8")) > 3100:
+      self.warning_count += 1
+      print('In policy %s: Warning: Length of description is more than 3100 '
+            'characters. It might exceed limit of 4096 characters in one of '
+            'its translations.' % (policy.get('name')))
 
     # If 'label' is present, it must be a string.
     self._CheckContains(policy, 'label', str, True)
diff --git a/components/security_interstitials/content/security_interstitial_tab_helper_unittest.cc b/components/security_interstitials/content/security_interstitial_tab_helper_unittest.cc
index 33c2101..d72a3ad 100644
--- a/components/security_interstitials/content/security_interstitial_tab_helper_unittest.cc
+++ b/components/security_interstitials/content/security_interstitial_tab_helper_unittest.cc
@@ -14,7 +14,7 @@
 #include "components/security_interstitials/core/controller_client.h"
 #include "components/security_interstitials/core/metrics_helper.h"
 #include "content/public/browser/certificate_request_result_type.h"
-#include "content/public/browser/navigation_handle.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/test_renderer_host.h"
 #include "net/base/net_errors.h"
 #include "net/test/cert_test_util.h"
@@ -70,8 +70,11 @@
   std::unique_ptr<content::NavigationHandle> CreateHandle(
       bool committed,
       bool is_same_document) {
-    return content::NavigationHandle::CreateNavigationHandleForTesting(
-        GURL(), main_rfh(), committed, net::OK, is_same_document);
+    std::unique_ptr<content::MockNavigationHandle> handle =
+        std::make_unique<content::MockNavigationHandle>(GURL(), main_rfh());
+    handle->set_has_committed(committed);
+    handle->set_is_same_document(is_same_document);
+    return handle;
   }
 
   // The lifetime of the blocking page is managed by the
@@ -170,6 +173,13 @@
   EXPECT_TRUE(blocking_page1_destroyed);
   EXPECT_FALSE(blocking_page2_destroyed);
   EXPECT_TRUE(blocking_page3_destroyed);
+
+  // Test that a subsequent committed navigation releases the last blocking
+  // page.
+  std::unique_ptr<content::NavigationHandle> committed_handle4 =
+      CreateHandle(true, false);
+  helper->DidFinishNavigation(committed_handle4.get());
+  EXPECT_TRUE(blocking_page2_destroyed);
 }
 
 // Tests that the helper properly handles a navigation that finishes without
diff --git a/components/signin/core/browser/BUILD.gn b/components/signin/core/browser/BUILD.gn
index c4d4177..8fd3fa5 100644
--- a/components/signin/core/browser/BUILD.gn
+++ b/components/signin/core/browser/BUILD.gn
@@ -230,6 +230,11 @@
     "fake_profile_oauth2_token_service.h",
     "fake_signin_manager.cc",
     "fake_signin_manager.h",
+
+    # TODO(https://crbug.com/907782): Move list_accounts_test_utils to
+    # //services/identity/public/cpp once FakeGCMS no longer depends on it.
+    "list_accounts_test_utils.cc",
+    "list_accounts_test_utils.h",
     "test_signin_client.cc",
     "test_signin_client.h",
   ]
diff --git a/components/signin/core/browser/account_investigator.cc b/components/signin/core/browser/account_investigator.cc
index eb3d15f..647b3ad 100644
--- a/components/signin/core/browser/account_investigator.cc
+++ b/components/signin/core/browser/account_investigator.cc
@@ -17,11 +17,10 @@
 #include "components/signin/core/browser/signin_pref_names.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/google_service_auth_error.h"
-#include "services/identity/public/cpp/identity_manager.h"
+#include "services/identity/public/cpp/accounts_in_cookie_jar_info.h"
 
 using base::Time;
 using base::TimeDelta;
-using gaia::ListedAccount;
 using signin_metrics::AccountRelation;
 using signin_metrics::ReportingType;
 
@@ -32,8 +31,8 @@
 const char kSignedInHashPrefix[] = "i";
 const char kSignedOutHashPrefix[] = "o";
 
-bool AreSame(const AccountInfo& info, const ListedAccount& account) {
-  return info.account_id == account.id;
+bool AreSame(const AccountInfo& info, const AccountInfo& account) {
+  return info.account_id == account.account_id;
 }
 
 }  // namespace
@@ -42,12 +41,9 @@
     TimeDelta::FromDays(1);
 
 AccountInvestigator::AccountInvestigator(
-    GaiaCookieManagerService* cookie_service,
     PrefService* pref_service,
     identity::IdentityManager* identity_manager)
-    : cookie_service_(cookie_service),
-      pref_service_(pref_service),
-      identity_manager_(identity_manager) {}
+    : pref_service_(pref_service), identity_manager_(identity_manager) {}
 
 AccountInvestigator::~AccountInvestigator() {}
 
@@ -59,7 +55,7 @@
 }
 
 void AccountInvestigator::Initialize() {
-  cookie_service_->AddObserver(this);
+  identity_manager_->AddObserver(this);
   previously_authenticated_ = identity_manager_->HasPrimaryAccount();
 
   Time previous = Time::FromDoubleT(
@@ -72,7 +68,7 @@
 }
 
 void AccountInvestigator::Shutdown() {
-  cookie_service_->RemoveObserver(this);
+  identity_manager_->RemoveObserver(this);
   timer_.Stop();
 }
 
@@ -84,9 +80,17 @@
   // called serveral times.
 }
 
+void AccountInvestigator::OnAccountsInCookieUpdated(
+    const identity::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
+    const GoogleServiceAuthError& error) {
+  OnGaiaAccountsInCookieUpdated(accounts_in_cookie_jar_info.signed_in_accounts,
+                                accounts_in_cookie_jar_info.signed_out_accounts,
+                                error);
+}
+
 void AccountInvestigator::OnGaiaAccountsInCookieUpdated(
-    const std::vector<ListedAccount>& signed_in_accounts,
-    const std::vector<ListedAccount>& signed_out_accounts,
+    const std::vector<AccountInfo>& signed_in_accounts,
+    const std::vector<AccountInfo>& signed_out_accounts,
     const GoogleServiceAuthError& error) {
   if (error != GoogleServiceAuthError::AuthErrorNone()) {
     // If we are pending periodic reporting, leave the flag set, and we will
@@ -136,19 +140,19 @@
 
 // static
 std::string AccountInvestigator::HashAccounts(
-    const std::vector<ListedAccount>& signed_in_accounts,
-    const std::vector<ListedAccount>& signed_out_accounts) {
+    const std::vector<AccountInfo>& signed_in_accounts,
+    const std::vector<AccountInfo>& signed_out_accounts) {
   std::vector<std::string> sorted_ids(signed_in_accounts.size());
   std::transform(std::begin(signed_in_accounts), std::end(signed_in_accounts),
                  std::back_inserter(sorted_ids),
-                 [](const ListedAccount& account) {
-                   return std::string(kSignedInHashPrefix) + account.id;
+                 [](const AccountInfo& account) {
+                   return std::string(kSignedInHashPrefix) + account.account_id;
                  });
-  std::transform(std::begin(signed_out_accounts), std::end(signed_out_accounts),
-                 std::back_inserter(sorted_ids),
-                 [](const ListedAccount& account) {
-                   return std::string(kSignedOutHashPrefix) + account.id;
-                 });
+  std::transform(
+      std::begin(signed_out_accounts), std::end(signed_out_accounts),
+      std::back_inserter(sorted_ids), [](const AccountInfo& account) {
+        return std::string(kSignedOutHashPrefix) + account.account_id;
+      });
   std::sort(sorted_ids.begin(), sorted_ids.end());
   std::ostringstream stream;
   std::copy(sorted_ids.begin(), sorted_ids.end(),
@@ -164,17 +168,17 @@
 // static
 AccountRelation AccountInvestigator::DiscernRelation(
     const AccountInfo& info,
-    const std::vector<ListedAccount>& signed_in_accounts,
-    const std::vector<ListedAccount>& signed_out_accounts) {
+    const std::vector<AccountInfo>& signed_in_accounts,
+    const std::vector<AccountInfo>& signed_out_accounts) {
   if (signed_in_accounts.empty() && signed_out_accounts.empty()) {
     return AccountRelation::EMPTY_COOKIE_JAR;
   }
   auto signed_in_match_iter = std::find_if(
       signed_in_accounts.begin(), signed_in_accounts.end(),
-      [&info](const ListedAccount& account) { return AreSame(info, account); });
+      [&info](const AccountInfo& account) { return AreSame(info, account); });
   auto signed_out_match_iter = std::find_if(
       signed_out_accounts.begin(), signed_out_accounts.end(),
-      [&info](const ListedAccount& account) { return AreSame(info, account); });
+      [&info](const AccountInfo& account) { return AreSame(info, account); });
   if (signed_in_match_iter != signed_in_accounts.end()) {
     if (signed_in_accounts.size() == 1) {
       return signed_out_accounts.empty()
@@ -199,18 +203,19 @@
 }
 
 void AccountInvestigator::TryPeriodicReport() {
-  std::vector<ListedAccount> signed_in_accounts, signed_out_accounts;
-  if (cookie_service_->ListAccounts(&signed_in_accounts,
-                                    &signed_out_accounts)) {
-    DoPeriodicReport(signed_in_accounts, signed_out_accounts);
+  auto accounts_in_cookie_jar_info =
+      identity_manager_->GetAccountsInCookieJar();
+  if (accounts_in_cookie_jar_info.accounts_are_fresh) {
+    DoPeriodicReport(accounts_in_cookie_jar_info.signed_in_accounts,
+                     accounts_in_cookie_jar_info.signed_out_accounts);
   } else {
     periodic_pending_ = true;
   }
 }
 
 void AccountInvestigator::DoPeriodicReport(
-    const std::vector<ListedAccount>& signed_in_accounts,
-    const std::vector<ListedAccount>& signed_out_accounts) {
+    const std::vector<AccountInfo>& signed_in_accounts,
+    const std::vector<AccountInfo>& signed_out_accounts) {
   SharedCookieJarReport(signed_in_accounts, signed_out_accounts, Time::Now(),
                         ReportingType::PERIODIC);
 
@@ -222,8 +227,8 @@
 }
 
 void AccountInvestigator::SharedCookieJarReport(
-    const std::vector<ListedAccount>& signed_in_accounts,
-    const std::vector<ListedAccount>& signed_out_accounts,
+    const std::vector<AccountInfo>& signed_in_accounts,
+    const std::vector<AccountInfo>& signed_out_accounts,
     const Time now,
     const ReportingType type) {
   const Time last_changed = Time::FromDoubleT(
@@ -251,8 +256,8 @@
 }
 
 void AccountInvestigator::SignedInAccountRelationReport(
-    const std::vector<ListedAccount>& signed_in_accounts,
-    const std::vector<ListedAccount>& signed_out_accounts,
+    const std::vector<AccountInfo>& signed_in_accounts,
+    const std::vector<AccountInfo>& signed_out_accounts,
     ReportingType type) {
   signin_metrics::LogAccountRelation(
       DiscernRelation(identity_manager_->GetPrimaryAccountInfo(),
diff --git a/components/signin/core/browser/account_investigator.h b/components/signin/core/browser/account_investigator.h
index 6fb9499..662117e8 100644
--- a/components/signin/core/browser/account_investigator.h
+++ b/components/signin/core/browser/account_investigator.h
@@ -11,10 +11,9 @@
 #include "base/macros.h"
 #include "base/timer/timer.h"
 #include "components/keyed_service/core/keyed_service.h"
-#include "components/signin/core/browser/gaia_cookie_manager_service.h"
+#include "services/identity/public/cpp/identity_manager.h"
 
 struct AccountInfo;
-class GaiaCookieManagerService;
 class PrefRegistrySimple;
 class PrefService;
 
@@ -23,8 +22,8 @@
 }  // namespace base
 
 namespace identity {
-class IdentityManager;
-}
+struct AccountsInCookieJarInfo;
+}  // namespace identity
 
 namespace signin_metrics {
 enum class AccountRelation;
@@ -36,15 +35,14 @@
 // is to watch for changes in relation between Chrome and content area accounts
 // and emit metrics about their relation.
 class AccountInvestigator : public KeyedService,
-                            public GaiaCookieManagerService::Observer {
+                            public identity::IdentityManager::Observer {
  public:
   // The targeted interval to perform periodic reporting. If chrome is not
   // active at the end of an interval, reporting will be done as soon as
   // possible.
   static const base::TimeDelta kPeriodicReportingInterval;
 
-  AccountInvestigator(GaiaCookieManagerService* cookie_service,
-                      PrefService* pref_service,
+  AccountInvestigator(PrefService* pref_service,
                       identity::IdentityManager* identity_manager);
   ~AccountInvestigator() override;
 
@@ -56,15 +54,21 @@
   // KeyedService:
   void Shutdown() override;
 
-  // GaiaCookieManagerService::Observer:
+  // identity::IdentityManager::Observer:
   void OnAddAccountToCookieCompleted(
       const std::string& account_id,
       const GoogleServiceAuthError& error) override;
-  void OnGaiaAccountsInCookieUpdated(
-      const std::vector<gaia::ListedAccount>& signed_in_accounts,
-      const std::vector<gaia::ListedAccount>& signed_out_accounts,
+  void OnAccountsInCookieUpdated(
+      const identity::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
       const GoogleServiceAuthError& error) override;
 
+  // Internal implementation of OnAccountsInCookieUpdated. It is public given
+  // that it is called directly by unittests.
+  void OnGaiaAccountsInCookieUpdated(
+      const std::vector<AccountInfo>& signed_in_accounts,
+      const std::vector<AccountInfo>& signed_out_accounts,
+      const GoogleServiceAuthError& error);
+
  private:
   friend class AccountInvestigatorTest;
 
@@ -77,16 +81,16 @@
   // Calculate a hash of the listed accounts. Order of accounts should not
   // affect the hashed values, but signed in and out status should.
   static std::string HashAccounts(
-      const std::vector<gaia::ListedAccount>& signed_in_accounts,
-      const std::vector<gaia::ListedAccount>& signed_out_accounts);
+      const std::vector<AccountInfo>& signed_in_accounts,
+      const std::vector<AccountInfo>& signed_out_accounts);
 
   // Compares the |info| object, which should correspond to the currently or
   // potentially signed into Chrome account, to the various account(s) in the
   // given cookie jar.
   static signin_metrics::AccountRelation DiscernRelation(
       const AccountInfo& info,
-      const std::vector<gaia::ListedAccount>& signed_in_accounts,
-      const std::vector<gaia::ListedAccount>& signed_out_accounts);
+      const std::vector<AccountInfo>& signed_in_accounts,
+      const std::vector<AccountInfo>& signed_out_accounts);
 
   // Tries to perform periodic reporting, potentially performing it now if the
   // cookie information is cached, otherwise sets things up to perform this
@@ -95,26 +99,24 @@
 
   // Performs periodic reporting with the given cookie jar data and restarts
   // the periodic reporting timer.
-  void DoPeriodicReport(
-      const std::vector<gaia::ListedAccount>& signed_in_accounts,
-      const std::vector<gaia::ListedAccount>& signed_out_accounts);
+  void DoPeriodicReport(const std::vector<AccountInfo>& signed_in_accounts,
+                        const std::vector<AccountInfo>& signed_out_accounts);
 
   // Performs the reporting that's shared between the periodic case and the
   // on change case.
   void SharedCookieJarReport(
-      const std::vector<gaia::ListedAccount>& signed_in_accounts,
-      const std::vector<gaia::ListedAccount>& signed_out_accounts,
+      const std::vector<AccountInfo>& signed_in_accounts,
+      const std::vector<AccountInfo>& signed_out_accounts,
       const base::Time now,
       const signin_metrics::ReportingType type);
 
   // Performs only the account relation reporting, which means comparing the
   // signed in account to the cookie jar accounts(s).
   void SignedInAccountRelationReport(
-      const std::vector<gaia::ListedAccount>& signed_in_accounts,
-      const std::vector<gaia::ListedAccount>& signed_out_accounts,
+      const std::vector<AccountInfo>& signed_in_accounts,
+      const std::vector<AccountInfo>& signed_out_accounts,
       signin_metrics::ReportingType type);
 
-  GaiaCookieManagerService* cookie_service_;
   PrefService* pref_service_;
   identity::IdentityManager* identity_manager_;
 
diff --git a/components/signin/core/browser/account_investigator_unittest.cc b/components/signin/core/browser/account_investigator_unittest.cc
index 8deaa43..5b231be5f 100644
--- a/components/signin/core/browser/account_investigator_unittest.cc
+++ b/components/signin/core/browser/account_investigator_unittest.cc
@@ -30,7 +30,6 @@
 using base::HistogramTester;
 using base::Time;
 using base::TimeDelta;
-using gaia::ListedAccount;
 using signin_metrics::AccountRelation;
 using signin_metrics::ReportingType;
 
@@ -51,9 +50,7 @@
                            &token_service_,
                            &signin_manager_,
                            &gaia_cookie_manager_service_),
-        investigator_(&gaia_cookie_manager_service_,
-                      &prefs_,
-                      identity_test_env_.identity_manager()) {
+        investigator_(&prefs_, identity_test_env_.identity_manager()) {
     AccountTrackerService::RegisterPrefs(prefs_.registry());
     AccountInvestigator::RegisterPrefs(prefs_.registry());
     SigninManagerBase::RegisterProfilePrefs(prefs_.registry());
@@ -77,20 +74,20 @@
                   const TimeDelta interval) {
     return AccountInvestigator::CalculatePeriodicDelay(previous, now, interval);
   }
-  std::string Hash(const std::vector<ListedAccount>& signed_in_accounts,
-                   const std::vector<ListedAccount>& signed_out_accounts) {
+  std::string Hash(const std::vector<AccountInfo>& signed_in_accounts,
+                   const std::vector<AccountInfo>& signed_out_accounts) {
     return AccountInvestigator::HashAccounts(signed_in_accounts,
                                              signed_out_accounts);
   }
   AccountRelation Relation(
       const AccountInfo& info,
-      const std::vector<ListedAccount>& signed_in_accounts,
-      const std::vector<ListedAccount>& signed_out_accounts) {
+      const std::vector<AccountInfo>& signed_in_accounts,
+      const std::vector<AccountInfo>& signed_out_accounts) {
     return AccountInvestigator::DiscernRelation(info, signed_in_accounts,
                                                 signed_out_accounts);
   }
-  void SharedReport(const std::vector<gaia::ListedAccount>& signed_in_accounts,
-                    const std::vector<gaia::ListedAccount>& signed_out_accounts,
+  void SharedReport(const std::vector<AccountInfo>& signed_in_accounts,
+                    const std::vector<AccountInfo>& signed_out_accounts,
                     const Time now,
                     const ReportingType type) {
     investigator_.SharedCookieJarReport(signed_in_accounts, signed_out_accounts,
@@ -103,11 +100,10 @@
   }
   base::OneShotTimer* timer() { return &investigator_.timer_; }
 
-  void ExpectRelationReport(
-      const std::vector<ListedAccount> signed_in_accounts,
-      const std::vector<ListedAccount> signed_out_accounts,
-      const ReportingType type,
-      const AccountRelation expected) {
+  void ExpectRelationReport(const std::vector<AccountInfo> signed_in_accounts,
+                            const std::vector<AccountInfo> signed_out_accounts,
+                            const ReportingType type,
+                            const AccountRelation expected) {
     HistogramTester histogram_tester;
     investigator_.SignedInAccountRelationReport(signed_in_accounts,
                                                 signed_out_accounts, type);
@@ -178,9 +174,9 @@
 
 namespace {
 
-ListedAccount Account(const std::string& id) {
-  ListedAccount account;
-  account.id = id;
+AccountInfo Account(const std::string& id) {
+  AccountInfo account;
+  account.account_id = id;
   return account;
 }
 
@@ -193,13 +189,13 @@
 // NOTE: IdentityTestEnvironment uses a prefix for generating gaia IDs:
 // "gaia_id_for_". For this reason, the tests prefix expected account IDs
 // used so that there is a match.
-const std::vector<ListedAccount> no_accounts{};
-const std::vector<ListedAccount> just_one{Account("gaia_id_for_1_mail.com")};
-const std::vector<ListedAccount> just_two{Account("gaia_id_for_2_mail.com")};
-const std::vector<ListedAccount> both{Account("gaia_id_for_1_mail.com"),
-                                      Account("gaia_id_for_2_mail.com")};
-const std::vector<ListedAccount> both_reversed{
-    Account("gaia_id_for_2_mail.com"), Account("gaia_id_for_1_mail.com")};
+const std::vector<AccountInfo> no_accounts{};
+const std::vector<AccountInfo> just_one{Account("gaia_id_for_1_mail.com")};
+const std::vector<AccountInfo> just_two{Account("gaia_id_for_2_mail.com")};
+const std::vector<AccountInfo> both{Account("gaia_id_for_1_mail.com"),
+                                    Account("gaia_id_for_2_mail.com")};
+const std::vector<AccountInfo> both_reversed{Account("gaia_id_for_2_mail.com"),
+                                             Account("gaia_id_for_1_mail.com")};
 
 const AccountInfo one(Info("gaia_id_for_1_mail.com"));
 const AccountInfo three(Info("gaia_id_for_3_mail.com"));
diff --git a/components/signin/core/browser/account_reconcilor_unittest.cc b/components/signin/core/browser/account_reconcilor_unittest.cc
index d42fbea..0e570f8 100644
--- a/components/signin/core/browser/account_reconcilor_unittest.cc
+++ b/components/signin/core/browser/account_reconcilor_unittest.cc
@@ -627,7 +627,7 @@
   }
 
   void ConfigureCookieManagerService(const std::vector<Cookie>& cookies) {
-    std::vector<FakeGaiaCookieManagerService::CookieParams> cookie_params;
+    std::vector<signin::CookieParams> cookie_params;
     for (const auto& cookie : cookies) {
       std::string gaia_id = cookie.gaia_id;
 
diff --git a/components/signin/core/browser/fake_gaia_cookie_manager_service.cc b/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
index 34146674..3e93f7ea 100644
--- a/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
+++ b/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
@@ -3,9 +3,9 @@
 // found in the LICENSE file.
 
 #include "components/signin/core/browser/fake_gaia_cookie_manager_service.h"
-
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "components/signin/core/browser/list_accounts_test_utils.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
@@ -49,59 +49,33 @@
 }
 
 void FakeGaiaCookieManagerService::SetListAccountsResponseHttpNotFound() {
-  test_url_loader_factory_->AddResponse(
-      GaiaUrls::GetInstance()
-          ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
-          .spec(),
-      /*content=*/"", net::HTTP_NOT_FOUND);
+  signin::SetListAccountsResponseHttpNotFound(test_url_loader_factory_);
 }
 
 void FakeGaiaCookieManagerService::SetListAccountsResponseWebLoginRequired() {
-  test_url_loader_factory_->AddResponse(
-      GaiaUrls::GetInstance()
-          ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
-          .spec(),
-      "Info=WebLoginRequired");
+  signin::SetListAccountsResponseWebLoginRequired(test_url_loader_factory_);
 }
 
 void FakeGaiaCookieManagerService::SetListAccountsResponseWithParams(
-    const std::vector<CookieParams>& params) {
-  std::vector<std::string> response_body;
-  for (const auto& param : params) {
-    std::string response_part = base::StringPrintf(
-        "[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d, \"%s\"",
-        param.email.c_str(), param.valid ? 1 : 0, param.gaia_id.c_str());
-    if (param.signed_out || !param.verified) {
-      response_part +=
-          base::StringPrintf(", null, null, null, %d, %d",
-                             param.signed_out ? 1 : 0, param.verified ? 1 : 0);
-    }
-    response_part += "]";
-    response_body.push_back(response_part);
-  }
-
-  test_url_loader_factory_->AddResponse(
-      GaiaUrls::GetInstance()
-          ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
-          .spec(),
-      std::string("[\"f\", [") + base::JoinString(response_body, ", ") + "]]");
+    const std::vector<signin::CookieParams>& params) {
+  signin::SetListAccountsResponseWithParams(params, test_url_loader_factory_);
 }
 
 void FakeGaiaCookieManagerService::SetListAccountsResponseNoAccounts() {
-  SetListAccountsResponseWithParams({});
+  signin::SetListAccountsResponseNoAccounts(test_url_loader_factory_);
 }
 
 void FakeGaiaCookieManagerService::SetListAccountsResponseOneAccount(
     const std::string& email,
     const std::string& gaia_id) {
-  CookieParams params = {email, gaia_id, true /* valid */,
-                         false /* signed_out */, true /* verified */};
-  SetListAccountsResponseWithParams({params});
+  signin::SetListAccountsResponseOneAccount(email, gaia_id,
+                                            test_url_loader_factory_);
 }
 
 void FakeGaiaCookieManagerService::SetListAccountsResponseOneAccountWithParams(
-    const CookieParams& params) {
-  SetListAccountsResponseWithParams({params});
+    const signin::CookieParams& params) {
+  signin::SetListAccountsResponseOneAccountWithParams(params,
+                                                      test_url_loader_factory_);
 }
 
 void FakeGaiaCookieManagerService::SetListAccountsResponseTwoAccounts(
@@ -109,11 +83,8 @@
     const std::string& gaia_id1,
     const std::string& email2,
     const std::string& gaia_id2) {
-  SetListAccountsResponseWithParams(
-      {{email1, gaia_id1, true /* valid */, false /* signed_out */,
-        true /* verified */},
-       {email2, gaia_id2, true /* valid */, false /* signed_out */,
-        true /* verified */}});
+  signin::SetListAccountsResponseTwoAccounts(email1, gaia_id1, email2, gaia_id2,
+                                             test_url_loader_factory_);
 }
 
 scoped_refptr<network::SharedURLLoaderFactory>
diff --git a/components/signin/core/browser/fake_gaia_cookie_manager_service.h b/components/signin/core/browser/fake_gaia_cookie_manager_service.h
index 3db6fd9..a8d8bb75 100644
--- a/components/signin/core/browser/fake_gaia_cookie_manager_service.h
+++ b/components/signin/core/browser/fake_gaia_cookie_manager_service.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
+#include "components/signin/core/browser/list_accounts_test_utils.h"
 #include "services/network/test/test_url_loader_factory.h"
 
 namespace network {
@@ -18,15 +19,6 @@
 
 class FakeGaiaCookieManagerService : public GaiaCookieManagerService {
  public:
-  // Parameters for the fake ListAccounts response.
-  struct CookieParams {
-    std::string email;
-    std::string gaia_id;
-    bool valid;
-    bool signed_out;
-    bool verified;
-  };
-
   FakeGaiaCookieManagerService(OAuth2TokenService* token_service,
                                SigninClient* client);
 
@@ -47,13 +39,14 @@
   void SetListAccountsResponseHttpNotFound();
   void SetListAccountsResponseWebLoginRequired();
   void SetListAccountsResponseWithParams(
-      const std::vector<CookieParams>& params);
+      const std::vector<signin::CookieParams>& params);
 
   // Helper methods, equivalent to calling SetListAccountsResponseWithParams().
   void SetListAccountsResponseNoAccounts();
   void SetListAccountsResponseOneAccount(const std::string& email,
                                          const std::string& gaia_id);
-  void SetListAccountsResponseOneAccountWithParams(const CookieParams& params);
+  void SetListAccountsResponseOneAccountWithParams(
+      const signin::CookieParams& params);
   void SetListAccountsResponseTwoAccounts(const std::string& email1,
                                           const std::string& gaia_id1,
                                           const std::string& email2,
diff --git a/components/signin/core/browser/list_accounts_test_utils.cc b/components/signin/core/browser/list_accounts_test_utils.cc
new file mode 100644
index 0000000..a8a41b2
--- /dev/null
+++ b/components/signin/core/browser/list_accounts_test_utils.cc
@@ -0,0 +1,93 @@
+// 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/signin/core/browser/list_accounts_test_utils.h"
+
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "services/network/test/test_url_loader_factory.h"
+
+namespace signin {
+
+using network::TestURLLoaderFactory;
+
+void SetListAccountsResponseHttpNotFound(
+    TestURLLoaderFactory* test_url_loader_factory) {
+  test_url_loader_factory->AddResponse(
+      GaiaUrls::GetInstance()
+          ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
+          .spec(),
+      /*content=*/"", net::HTTP_NOT_FOUND);
+}
+
+void SetListAccountsResponseWebLoginRequired(
+    TestURLLoaderFactory* test_url_loader_factory) {
+  test_url_loader_factory->AddResponse(
+      GaiaUrls::GetInstance()
+          ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
+          .spec(),
+      "Info=WebLoginRequired");
+}
+
+void SetListAccountsResponseWithParams(
+    const std::vector<CookieParams>& params,
+    TestURLLoaderFactory* test_url_loader_factory) {
+  std::vector<std::string> response_body;
+  for (const auto& param : params) {
+    std::string response_part = base::StringPrintf(
+        "[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d, \"%s\"",
+        param.email.c_str(), param.valid ? 1 : 0, param.gaia_id.c_str());
+    if (param.signed_out || !param.verified) {
+      response_part +=
+          base::StringPrintf(", null, null, null, %d, %d",
+                             param.signed_out ? 1 : 0, param.verified ? 1 : 0);
+    }
+    response_part += "]";
+    response_body.push_back(response_part);
+  }
+
+  test_url_loader_factory->AddResponse(
+      GaiaUrls::GetInstance()
+          ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
+          .spec(),
+      std::string("[\"f\", [") + base::JoinString(response_body, ", ") + "]]");
+}
+
+void SetListAccountsResponseNoAccounts(
+    TestURLLoaderFactory* test_url_loader_factory) {
+  SetListAccountsResponseWithParams({}, test_url_loader_factory);
+}
+
+void SetListAccountsResponseOneAccount(
+    const std::string& email,
+    const std::string& gaia_id,
+    TestURLLoaderFactory* test_url_loader_factory) {
+  CookieParams params = {email, gaia_id, /*valid=*/true,
+                         /*signed_out=*/false, /*verified=*/true};
+  SetListAccountsResponseWithParams({params}, test_url_loader_factory);
+}
+
+void SetListAccountsResponseOneAccountWithParams(
+    const CookieParams& params,
+    TestURLLoaderFactory* test_url_loader_factory) {
+  SetListAccountsResponseWithParams({params}, test_url_loader_factory);
+}
+
+void SetListAccountsResponseTwoAccounts(
+    const std::string& email1,
+    const std::string& gaia_id1,
+    const std::string& email2,
+    const std::string& gaia_id2,
+    TestURLLoaderFactory* test_url_loader_factory) {
+  SetListAccountsResponseWithParams(
+      {{email1, gaia_id1, /*valid=*/true, /*signed_out=*/false,
+        /*verified=*/true},
+       {email2, gaia_id2, /*valid=*/true, /*signed_out=*/false,
+        /*verified=*/true}},
+      test_url_loader_factory);
+}
+
+}  // namespace signin
diff --git a/components/signin/core/browser/list_accounts_test_utils.h b/components/signin/core/browser/list_accounts_test_utils.h
new file mode 100644
index 0000000..9a5d897
--- /dev/null
+++ b/components/signin/core/browser/list_accounts_test_utils.h
@@ -0,0 +1,67 @@
+// 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_SIGNIN_CORE_BROWSER_LIST_ACCOUNTS_TEST_UTILS_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_LIST_ACCOUNTS_TEST_UTILS_H_
+
+#include <string>
+#include <vector>
+
+namespace network {
+class TestURLLoaderFactory;
+}  // namespace network
+
+namespace signin {
+
+// Parameters for the fake ListAccounts response.
+struct CookieParams {
+  std::string email;
+  std::string gaia_id;
+  bool valid;
+  bool signed_out;
+  bool verified;
+};
+
+// Make ListAccounts call return NotFound.
+void SetListAccountsResponseHttpNotFound(
+    network::TestURLLoaderFactory* test_url_loader_factory);
+
+// Make ListAccounts call return Info=WebLoginRequired.
+void SetListAccountsResponseWebLoginRequired(
+    network::TestURLLoaderFactory* test_url_loader_factory);
+
+// Make ListAccounts return a list of accounts based on the provided |params|.
+void SetListAccountsResponseWithParams(
+    const std::vector<CookieParams>& params,
+    network::TestURLLoaderFactory* test_url_loader_factory);
+
+// Helper methods, equivalent to calling
+// SetListAccountsResponseWithParams().
+
+// Make ListAccounts return no accounts.
+void SetListAccountsResponseNoAccounts(
+    network::TestURLLoaderFactory* test_url_loader_factory);
+
+// Make ListAccounts return one account with the provided |email| and
+// |gaia_id|.
+void SetListAccountsResponseOneAccount(
+    const std::string& email,
+    const std::string& gaia_id,
+    network::TestURLLoaderFactory* test_url_loader_factory);
+
+// Make ListAccounts return one account based on the provided |params|.
+void SetListAccountsResponseOneAccountWithParams(
+    const CookieParams& params,
+    network::TestURLLoaderFactory* test_url_loader_factory);
+
+// Make ListAccounts return two accounts with the provided emails and gaia_ids.
+void SetListAccountsResponseTwoAccounts(
+    const std::string& email1,
+    const std::string& gaia_id1,
+    const std::string& email2,
+    const std::string& gaia_id2,
+    network::TestURLLoaderFactory* test_url_loader_factory);
+
+}  // namespace signin
+
+#endif  // COMPONENTS_SIGNIN_CORE_BROWSER_LIST_ACCOUNTS_TEST_UTILS_H_
diff --git a/components/signin/core/browser/signin_error_controller.cc b/components/signin/core/browser/signin_error_controller.cc
index e42abef..db65bb68 100644
--- a/components/signin/core/browser/signin_error_controller.cc
+++ b/components/signin/core/browser/signin_error_controller.cc
@@ -6,22 +6,15 @@
 
 #include "components/signin/core/browser/signin_metrics.h"
 
-SigninErrorController::SigninErrorController(AccountMode mode,
-                                             OAuth2TokenService* token_service,
-                                             SigninManagerBase* signin_manager)
+SigninErrorController::SigninErrorController(
+    AccountMode mode,
+    identity::IdentityManager* identity_manager)
     : account_mode_(mode),
-      token_service_(token_service),
-      signin_manager_(signin_manager),
-      scoped_token_service_observer_(this),
-      scoped_signin_manager_observer_(this),
+      identity_manager_(identity_manager),
+      scoped_identity_manager_observer_(this),
       auth_error_(GoogleServiceAuthError::AuthErrorNone()) {
-  DCHECK(token_service_);
-  scoped_token_service_observer_.Add(token_service_);
-
-  if (account_mode_ == AccountMode::PRIMARY_ACCOUNT) {
-    DCHECK(signin_manager_);
-    scoped_signin_manager_observer_.Add(signin_manager_);
-  }
+  DCHECK(identity_manager_);
+  scoped_identity_manager_observer_.Add(identity_manager_);
 
   Update();
 }
@@ -29,10 +22,7 @@
 SigninErrorController::~SigninErrorController() = default;
 
 void SigninErrorController::Shutdown() {
-  scoped_token_service_observer_.RemoveAll();
-
-  if (account_mode_ == AccountMode::PRIMARY_ACCOUNT)
-    scoped_signin_manager_observer_.RemoveAll();
+  scoped_identity_manager_observer_.RemoveAll();
 }
 
 void SigninErrorController::Update() {
@@ -44,18 +34,23 @@
   // actionable error state and some provider exposes a similar error and
   // account id, use that error. Otherwise, just take the first actionable
   // error we find.
-  for (const std::string& account_id : token_service_->GetAccounts()) {
+  for (const AccountInfo& account_info :
+       identity_manager_->GetAccountsWithRefreshTokens()) {
+    std::string account_id = account_info.account_id;
+
     // In PRIMARY_ACCOUNT mode, ignore all secondary accounts.
     if (account_mode_ == AccountMode::PRIMARY_ACCOUNT &&
-        (account_id != signin_manager_->GetAuthenticatedAccountId())) {
+        (account_id != identity_manager_->GetPrimaryAccountId())) {
       continue;
     }
 
-    if (!token_service_->RefreshTokenHasError(account_id))
+    if (!identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
+            account_id))
       continue;
 
-    GoogleServiceAuthError error = token_service_->GetAuthError(account_id);
-    // TokenService only reports persistent errors.
+    GoogleServiceAuthError error =
+        identity_manager_->GetErrorStateOfRefreshTokenForAccount(account_id);
+    // IdentityManager only reports persistent errors.
     DCHECK(error.IsPersistentError());
 
     // Prioritize this error if it matches the previous |auth_error_|.
@@ -102,23 +97,30 @@
   observer_list_.RemoveObserver(observer);
 }
 
-void SigninErrorController::OnEndBatchChanges() {
+void SigninErrorController::OnEndBatchOfRefreshTokenStateChanges() {
   Update();
 }
 
-void SigninErrorController::OnAuthErrorChanged(
-    const std::string& account_id,
-    const GoogleServiceAuthError& auth_error) {
+void SigninErrorController::OnErrorStateOfRefreshTokenUpdatedForAccount(
+    const AccountInfo& account_info,
+    const GoogleServiceAuthError& error) {
   Update();
 }
 
-void SigninErrorController::GoogleSigninSucceeded(
-    const AccountInfo& account_info) {
-  DCHECK(account_mode_ == AccountMode::PRIMARY_ACCOUNT);
+void SigninErrorController::OnPrimaryAccountSet(
+    const AccountInfo& primary_account_info) {
+  // Ignore updates to the primary account if not in PRIMARY_ACCOUNT mode.
+  if (account_mode_ != AccountMode::PRIMARY_ACCOUNT)
+    return;
+
   Update();
 }
 
-void SigninErrorController::GoogleSignedOut(const AccountInfo& account_info) {
-  DCHECK(account_mode_ == AccountMode::PRIMARY_ACCOUNT);
+void SigninErrorController::OnPrimaryAccountCleared(
+    const AccountInfo& previous_primary_account_info) {
+  // Ignore updates to the primary account if not in PRIMARY_ACCOUNT mode.
+  if (account_mode_ != AccountMode::PRIMARY_ACCOUNT)
+    return;
+
   Update();
 }
diff --git a/components/signin/core/browser/signin_error_controller.h b/components/signin/core/browser/signin_error_controller.h
index 0ed6301a..3aca2d2 100644
--- a/components/signin/core/browser/signin_error_controller.h
+++ b/components/signin/core/browser/signin_error_controller.h
@@ -11,17 +11,15 @@
 #include "base/observer_list.h"
 #include "base/scoped_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
-#include "components/signin/core/browser/signin_manager_base.h"
 #include "google_apis/gaia/google_service_auth_error.h"
-#include "google_apis/gaia/oauth2_token_service.h"
+#include "services/identity/public/cpp/identity_manager.h"
 
 // Keep track of auth errors and expose them to observers in the UI. Services
 // that wish to expose auth errors to the user should register an
 // AuthStatusProvider to report their current authentication state, and should
 // invoke AuthStatusChanged() when their authentication state may have changed.
 class SigninErrorController : public KeyedService,
-                              public OAuth2TokenService::Observer,
-                              public SigninManagerBase::Observer {
+                              public identity::IdentityManager::Observer {
  public:
   enum class AccountMode {
     // Signin error controller monitors all the accounts. When multiple accounts
@@ -42,8 +40,7 @@
   };
 
   SigninErrorController(AccountMode mode,
-                        OAuth2TokenService* token_service,
-                        SigninManagerBase* signin_manager);
+                        identity::IdentityManager* identity_manager);
   ~SigninErrorController() override;
 
   // KeyedService implementation:
@@ -62,25 +59,20 @@
   // Invoked when the auth status has changed.
   void Update();
 
-  // OAuth2TokenService::Observer implementation:
-  void OnEndBatchChanges() override;
-  void OnAuthErrorChanged(const std::string& account_id,
-                          const GoogleServiceAuthError& auth_error) override;
-
-  // SigninManagerBase::Observer implementation:
-  void GoogleSigninSucceeded(const AccountInfo& account_info) override;
-  void GoogleSignedOut(const AccountInfo& account_info) override;
+  // identity::IdentityManager::Observer:
+  void OnEndBatchOfRefreshTokenStateChanges() override;
+  void OnErrorStateOfRefreshTokenUpdatedForAccount(
+      const AccountInfo& account_info,
+      const GoogleServiceAuthError& error) override;
+  void OnPrimaryAccountSet(const AccountInfo& primary_account_info) override;
+  void OnPrimaryAccountCleared(
+      const AccountInfo& previous_primary_account_info) override;
 
   const AccountMode account_mode_;
-  OAuth2TokenService* token_service_;
+  identity::IdentityManager* identity_manager_;
 
-  // Used only in PRIMARY_ACCOUNT mode, where it must be non-null; otherwise,
-  // may be null.
-  SigninManagerBase* signin_manager_;
-  ScopedObserver<OAuth2TokenService, SigninErrorController>
-      scoped_token_service_observer_;
-  ScopedObserver<SigninManagerBase, SigninErrorController>
-      scoped_signin_manager_observer_;
+  ScopedObserver<identity::IdentityManager, SigninErrorController>
+      scoped_identity_manager_observer_;
 
   // The account that generated the last auth error.
   std::string error_account_id_;
diff --git a/components/signin/core/browser/signin_error_controller_unittest.cc b/components/signin/core/browser/signin_error_controller_unittest.cc
index 7dee3ca..2b88b04cf 100644
--- a/components/signin/core/browser/signin_error_controller_unittest.cc
+++ b/components/signin/core/browser/signin_error_controller_unittest.cc
@@ -12,19 +12,15 @@
 #include "base/scoped_observer.h"
 #include "base/stl_util.h"
 #include "base/test/scoped_task_environment.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/fake_gaia_cookie_manager_service.h"
-#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
-#include "components/signin/core/browser/fake_signin_manager.h"
-#include "components/signin/core/browser/test_signin_client.h"
+#include "services/identity/public/cpp/identity_test_environment.h"
+#include "services/identity/public/cpp/primary_account_mutator.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
 
-static const char kTestAccountId[] = "account_id";
-static const char kOtherTestAccountId[] = "other_id";
+static const char kTestEmail[] = "me@test.com";
+static const char kOtherTestEmail[] = "you@test.com";
 
 class MockSigninErrorControllerObserver
     : public SigninErrorController::Observer {
@@ -38,27 +34,31 @@
   MockSigninErrorControllerObserver observer;
   EXPECT_CALL(observer, OnErrorChanged()).Times(0);
 
-  TestingPrefServiceSimple pref_service;
-  FakeProfileOAuth2TokenService token_service(&pref_service);
+  base::test::ScopedTaskEnvironment task_environment;
+  identity::IdentityTestEnvironment identity_test_env;
   SigninErrorController error_controller(
-      SigninErrorController::AccountMode::ANY_ACCOUNT, &token_service, nullptr);
+      SigninErrorController::AccountMode::ANY_ACCOUNT,
+      identity_test_env.identity_manager());
   ScopedObserver<SigninErrorController, SigninErrorController::Observer>
       scoped_observer(&observer);
   scoped_observer.Add(&error_controller);
   ASSERT_FALSE(error_controller.HasError());
   ::testing::Mock::VerifyAndClearExpectations(&observer);
 
-  // The fake token service does not call OnEndBatchChanges() as part of
-  // UpdateCredentials(), and thus the signin error controller is not updated.
+  // IdentityTestEnvironment does not call OnEndBatchChanges() as part of
+  // MakeAccountAvailable(), and thus the signin error controller is not
+  // updated.
   EXPECT_CALL(observer, OnErrorChanged()).Times(0);
 
-  token_service.UpdateCredentials(kTestAccountId, "token");
+  std::string test_account_id =
+      identity_test_env.MakeAccountAvailable(kTestEmail).account_id;
   ::testing::Mock::VerifyAndClearExpectations(&observer);
 
   GoogleServiceAuthError error1 =
       GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
   EXPECT_CALL(observer, OnErrorChanged()).Times(1);
-  token_service.UpdateAuthErrorForTesting(kTestAccountId, error1);
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      test_account_id, error1);
   EXPECT_TRUE(error_controller.HasError());
   EXPECT_EQ(error1, error_controller.auth_error());
   ::testing::Mock::VerifyAndClearExpectations(&observer);
@@ -66,14 +66,15 @@
   GoogleServiceAuthError error2 =
       GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED);
   EXPECT_CALL(observer, OnErrorChanged()).Times(1);
-  token_service.UpdateAuthErrorForTesting(kTestAccountId, error2);
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      test_account_id, error2);
   EXPECT_TRUE(error_controller.HasError());
   EXPECT_EQ(error2, error_controller.auth_error());
   ::testing::Mock::VerifyAndClearExpectations(&observer);
 
   EXPECT_CALL(observer, OnErrorChanged()).Times(1);
-  token_service.UpdateAuthErrorForTesting(
-      kTestAccountId, GoogleServiceAuthError::AuthErrorNone());
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      test_account_id, GoogleServiceAuthError::AuthErrorNone());
   EXPECT_FALSE(error_controller.HasError());
   EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
             error_controller.auth_error());
@@ -81,26 +82,30 @@
 }
 
 TEST(SigninErrorControllerTest, AccountTransitionAnyAccount) {
-  TestingPrefServiceSimple pref_service;
-  FakeProfileOAuth2TokenService token_service(&pref_service);
-  token_service.UpdateCredentials(kTestAccountId, "token");
-  token_service.UpdateCredentials(kOtherTestAccountId, "token");
+  base::test::ScopedTaskEnvironment task_environment;
+  identity::IdentityTestEnvironment identity_test_env;
+
+  std::string test_account_id =
+      identity_test_env.MakeAccountAvailable(kTestEmail).account_id;
+  std::string other_test_account_id =
+      identity_test_env.MakeAccountAvailable(kOtherTestEmail).account_id;
   SigninErrorController error_controller(
-      SigninErrorController::AccountMode::ANY_ACCOUNT, &token_service, nullptr);
+      SigninErrorController::AccountMode::ANY_ACCOUNT,
+      identity_test_env.identity_manager());
   ASSERT_FALSE(error_controller.HasError());
 
-  token_service.UpdateAuthErrorForTesting(
-      kTestAccountId,
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      test_account_id,
       GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
-  token_service.UpdateAuthErrorForTesting(
-      kOtherTestAccountId,
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      other_test_account_id,
       GoogleServiceAuthError(GoogleServiceAuthError::NONE));
   ASSERT_TRUE(error_controller.HasError());
-  ASSERT_STREQ(kTestAccountId, error_controller.error_account_id().c_str());
+  ASSERT_EQ(test_account_id, error_controller.error_account_id());
 
   // Now resolve the auth errors - the menu item should go away.
-  token_service.UpdateAuthErrorForTesting(
-      kTestAccountId, GoogleServiceAuthError::AuthErrorNone());
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      test_account_id, GoogleServiceAuthError::AuthErrorNone());
   ASSERT_FALSE(error_controller.HasError());
 }
 
@@ -109,70 +114,62 @@
 #if !defined(OS_CHROMEOS)
 TEST(SigninErrorControllerTest, AccountTransitionPrimaryAccount) {
   base::test::ScopedTaskEnvironment task_environment;
+  identity::IdentityTestEnvironment identity_test_env;
+  identity::PrimaryAccountMutator* primary_account_mutator =
+      identity_test_env.identity_manager()->GetPrimaryAccountMutator();
 
-  TestingPrefServiceSimple pref_service;
-  FakeProfileOAuth2TokenService token_service(&pref_service);
-  ProfileOAuth2TokenService::RegisterProfilePrefs(pref_service.registry());
-  TestSigninClient signin_client(&pref_service);
-  AccountTrackerService account_tracker;
-  AccountTrackerService::RegisterPrefs(pref_service.registry());
-  account_tracker.Initialize(&pref_service, base::FilePath());
-  FakeGaiaCookieManagerService cookie_manager_service(&token_service,
-                                                      &signin_client);
-  FakeSigninManager signin_manager(&signin_client, &token_service,
-                                   &account_tracker, &cookie_manager_service);
-  SigninManagerBase::RegisterProfilePrefs(pref_service.registry());
-  SigninManagerBase::RegisterPrefs(pref_service.registry());
-  signin_manager.Initialize(nullptr);
-
-  token_service.UpdateCredentials(kTestAccountId, "token");
-  token_service.UpdateCredentials(kOtherTestAccountId, "token");
+  std::string test_account_id =
+      identity_test_env.MakeAccountAvailable(kTestEmail).account_id;
+  std::string other_test_account_id =
+      identity_test_env.MakeAccountAvailable(kOtherTestEmail).account_id;
   SigninErrorController error_controller(
-      SigninErrorController::AccountMode::PRIMARY_ACCOUNT, &token_service,
-      &signin_manager);
+      SigninErrorController::AccountMode::PRIMARY_ACCOUNT,
+      identity_test_env.identity_manager());
   ASSERT_FALSE(error_controller.HasError());
 
-  token_service.UpdateAuthErrorForTesting(
-      kTestAccountId,
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      test_account_id,
       GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
-  token_service.UpdateAuthErrorForTesting(
-      kOtherTestAccountId,
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      other_test_account_id,
       GoogleServiceAuthError(GoogleServiceAuthError::NONE));
   ASSERT_FALSE(error_controller.HasError());  // No primary account.
 
   // Set the primary account.
-  signin_manager.SignIn(kOtherTestAccountId, kOtherTestAccountId, "");
+  identity_test_env.SetPrimaryAccount(kOtherTestEmail);
 
   ASSERT_FALSE(error_controller.HasError());  // Error is on secondary.
 
   // Change the primary account to the account with an error and check that the
   // error controller updates its error status accordingly.
-  signin_manager.SignOutAndKeepAllAccounts(
+  primary_account_mutator->ClearPrimaryAccount(
+      identity::PrimaryAccountMutator::ClearAccountsAction::kKeepAll,
       signin_metrics::FORCE_SIGNOUT_ALWAYS_ALLOWED_FOR_TEST,
       signin_metrics::SignoutDelete::IGNORE_METRIC);
-  signin_manager.SignIn(kTestAccountId, kTestAccountId, "");
+  identity_test_env.SetPrimaryAccount(kTestEmail);
   ASSERT_TRUE(error_controller.HasError());
-  ASSERT_STREQ(kTestAccountId, error_controller.error_account_id().c_str());
+  ASSERT_EQ(test_account_id, error_controller.error_account_id());
 
-  token_service.UpdateAuthErrorForTesting(
-      kOtherTestAccountId,
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      other_test_account_id,
       GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
   ASSERT_TRUE(error_controller.HasError());
-  ASSERT_STREQ(kTestAccountId, error_controller.error_account_id().c_str());
+  ASSERT_EQ(test_account_id, error_controller.error_account_id());
 
   // Change the primary account again and check that the error controller
   // updates its error status accordingly.
-  signin_manager.SignOutAndKeepAllAccounts(
+  primary_account_mutator->ClearPrimaryAccount(
+      identity::PrimaryAccountMutator::ClearAccountsAction::kKeepAll,
       signin_metrics::FORCE_SIGNOUT_ALWAYS_ALLOWED_FOR_TEST,
       signin_metrics::SignoutDelete::IGNORE_METRIC);
-  signin_manager.SignIn(kOtherTestAccountId, kOtherTestAccountId, "");
+  identity_test_env.SetPrimaryAccount(kOtherTestEmail);
   ASSERT_TRUE(error_controller.HasError());
-  ASSERT_STREQ(kOtherTestAccountId,
-               error_controller.error_account_id().c_str());
+  ASSERT_EQ(other_test_account_id, error_controller.error_account_id());
 
   // Sign out and check that that the error controller updates its error status
   // accordingly.
-  signin_manager.SignOutAndKeepAllAccounts(
+  primary_account_mutator->ClearPrimaryAccount(
+      identity::PrimaryAccountMutator::ClearAccountsAction::kKeepAll,
       signin_metrics::FORCE_SIGNOUT_ALWAYS_ALLOWED_FOR_TEST,
       signin_metrics::SignoutDelete::IGNORE_METRIC);
   ASSERT_FALSE(error_controller.HasError());
@@ -181,11 +178,14 @@
 
 // Verify that SigninErrorController handles errors properly.
 TEST(SigninErrorControllerTest, AuthStatusEnumerateAllErrors) {
-  TestingPrefServiceSimple pref_service;
-  FakeProfileOAuth2TokenService token_service(&pref_service);
-  token_service.UpdateCredentials(kTestAccountId, "token");
+  base::test::ScopedTaskEnvironment task_environment;
+  identity::IdentityTestEnvironment identity_test_env;
+
+  std::string test_account_id =
+      identity_test_env.MakeAccountAvailable(kTestEmail).account_id;
   SigninErrorController error_controller(
-      SigninErrorController::AccountMode::ANY_ACCOUNT, &token_service, nullptr);
+      SigninErrorController::AccountMode::ANY_ACCOUNT,
+      identity_test_env.identity_manager());
 
   GoogleServiceAuthError::State table[] = {
       GoogleServiceAuthError::NONE,
@@ -214,71 +214,74 @@
     if (error.IsTransientError())
       continue;  // Only persistent errors or non-errors are reported.
 
-    token_service.UpdateAuthErrorForTesting(kTestAccountId, error);
+    identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+        test_account_id, error);
 
     EXPECT_EQ(error_controller.HasError(), error.IsPersistentError());
 
     if (error.IsPersistentError()) {
       EXPECT_EQ(state, error_controller.auth_error().state());
-      EXPECT_STREQ(kTestAccountId, error_controller.error_account_id().c_str());
+      EXPECT_EQ(test_account_id, error_controller.error_account_id());
     } else {
       EXPECT_EQ(GoogleServiceAuthError::NONE,
                 error_controller.auth_error().state());
-      EXPECT_STREQ("", error_controller.error_account_id().c_str());
+      EXPECT_EQ("", error_controller.error_account_id());
     }
   }
 }
 
 // Verify that existing error is not replaced by new error.
 TEST(SigninErrorControllerTest, AuthStatusChange) {
-  TestingPrefServiceSimple pref_service;
-  FakeProfileOAuth2TokenService token_service(&pref_service);
-  token_service.UpdateCredentials(kTestAccountId, "token");
-  token_service.UpdateCredentials(kOtherTestAccountId, "token");
+  base::test::ScopedTaskEnvironment task_environment;
+  identity::IdentityTestEnvironment identity_test_env;
+
+  std::string test_account_id =
+      identity_test_env.MakeAccountAvailable(kTestEmail).account_id;
+  std::string other_test_account_id =
+      identity_test_env.MakeAccountAvailable(kOtherTestEmail).account_id;
   SigninErrorController error_controller(
-      SigninErrorController::AccountMode::ANY_ACCOUNT, &token_service, nullptr);
+      SigninErrorController::AccountMode::ANY_ACCOUNT,
+      identity_test_env.identity_manager());
   ASSERT_FALSE(error_controller.HasError());
 
-  // Set an error for kOtherTestAccountId.
-  token_service.UpdateAuthErrorForTesting(
-      kTestAccountId, GoogleServiceAuthError(GoogleServiceAuthError::NONE));
-  token_service.UpdateAuthErrorForTesting(
-      kOtherTestAccountId,
+  // Set an error for other_test_account_id.
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      test_account_id, GoogleServiceAuthError(GoogleServiceAuthError::NONE));
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      other_test_account_id,
       GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
   ASSERT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS,
             error_controller.auth_error().state());
-  ASSERT_STREQ(kOtherTestAccountId,
-               error_controller.error_account_id().c_str());
+  ASSERT_EQ(other_test_account_id, error_controller.error_account_id());
 
-  // Change the error for kOtherTestAccountId.
-  token_service.UpdateAuthErrorForTesting(
-      kOtherTestAccountId,
+  // Change the error for other_test_account_id.
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      other_test_account_id,
       GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_ERROR));
   ASSERT_EQ(GoogleServiceAuthError::SERVICE_ERROR,
             error_controller.auth_error().state());
-  ASSERT_STREQ(kOtherTestAccountId,
-               error_controller.error_account_id().c_str());
+  ASSERT_EQ(other_test_account_id, error_controller.error_account_id());
 
-  // Set the error for kTestAccountId -- nothing should change.
-  token_service.UpdateAuthErrorForTesting(
-      kTestAccountId, GoogleServiceAuthError(
-                          GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE));
+  // Set the error for test_account_id -- nothing should change.
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      test_account_id,
+      GoogleServiceAuthError(
+          GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE));
   ASSERT_EQ(GoogleServiceAuthError::SERVICE_ERROR,
             error_controller.auth_error().state());
-  ASSERT_STREQ(kOtherTestAccountId,
-               error_controller.error_account_id().c_str());
+  ASSERT_EQ(other_test_account_id, error_controller.error_account_id());
 
-  // Clear the error for kOtherTestAccountId, so the kTestAccountId's error is
-  // used.
-  token_service.UpdateAuthErrorForTesting(
-      kOtherTestAccountId,
+  // Clear the error for other_test_account_id, so the test_account_id's error
+  // is used.
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      other_test_account_id,
       GoogleServiceAuthError(GoogleServiceAuthError::NONE));
   ASSERT_EQ(GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE,
             error_controller.auth_error().state());
-  ASSERT_STREQ(kTestAccountId, error_controller.error_account_id().c_str());
+  ASSERT_EQ(test_account_id, error_controller.error_account_id());
 
   // Clear the remaining error.
-  token_service.UpdateAuthErrorForTesting(
-      kTestAccountId, GoogleServiceAuthError(GoogleServiceAuthError::NONE));
+  identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+      test_account_id, GoogleServiceAuthError(GoogleServiceAuthError::NONE));
   ASSERT_FALSE(error_controller.HasError());
 }
diff --git a/components/signin/core/browser/signin_metrics.cc b/components/signin/core/browser/signin_metrics.cc
index 224ae04..7c0bf86 100644
--- a/components/signin/core/browser/signin_metrics.cc
+++ b/components/signin/core/browser/signin_metrics.cc
@@ -118,6 +118,10 @@
       base::RecordAction(
           base::UserMetricsAction("Signin_Signin_FromMachineLogon"));
       break;
+    case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
+      base::RecordAction(
+          base::UserMetricsAction("Signin_Signin_FromGoogleServicesSettings"));
+      break;
     case AccessPoint::ACCESS_POINT_MAX:
       NOTREACHED();
       break;
@@ -186,6 +190,7 @@
     case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
     case AccessPoint::ACCESS_POINT_UNKNOWN:
     case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+    case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
       NOTREACHED() << "Signin_SigninWithDefault_From* user actions"
                    << " are not recorded for access_point "
                    << static_cast<int>(access_point)
@@ -259,6 +264,7 @@
     case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
     case AccessPoint::ACCESS_POINT_UNKNOWN:
     case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+    case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
       NOTREACHED() << "Signin_SigninNotDefault_From* user actions"
                    << " are not recorded for access point "
                    << static_cast<int>(access_point)
@@ -332,6 +338,7 @@
     case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
     case AccessPoint::ACCESS_POINT_UNKNOWN:
     case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+    case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
       // These access points do not support personalized sign-in promos, so
       // |Signin_SigninNewAccountPreDice_From*| user actions should not
       // be recorded for them. Note: To avoid bloating the sign-in APIs, the
@@ -416,6 +423,7 @@
     case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
     case AccessPoint::ACCESS_POINT_UNKNOWN:
     case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+    case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
       // These access points do not support personalized sign-in promos, so
       // |Signin_SigninNewAccountNoExistingAccount_From*| user actions should
       // not be recorded for them. Note: To avoid bloating the sign-in APIs, the
@@ -496,6 +504,7 @@
     case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
     case AccessPoint::ACCESS_POINT_UNKNOWN:
     case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+    case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
       // These access points do not support personalized sign-in promos, so
       // |Signin_SigninNewAccountExistingAccount_From*| user actions should not
       // be recorded for them. Note: To avoid bloating the sign-in APIs, the
@@ -945,6 +954,10 @@
       base::RecordAction(
           base::UserMetricsAction("Signin_Impression_FromManageCardsBubble"));
       break;
+    case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
+      base::RecordAction(base::UserMetricsAction(
+          "Signin_Impression_FromGoogleServicesSettings"));
+      break;
     case AccessPoint::ACCESS_POINT_CONTENT_AREA:
     case AccessPoint::ACCESS_POINT_EXTENSIONS:
     case AccessPoint::ACCESS_POINT_SUPERVISED_USER:
@@ -1079,6 +1092,7 @@
     case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
     case AccessPoint::ACCESS_POINT_UNKNOWN:
     case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+    case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
       NOTREACHED() << "Signin_Impression{With|WithNo}Account_From* user actions"
                    << " are not recorded for access point "
                    << static_cast<int>(access_point)
diff --git a/components/signin/core/browser/signin_metrics.h b/components/signin/core/browser/signin_metrics.h
index edbd8d39..dcd0aeb 100644
--- a/components/signin/core/browser/signin_metrics.h
+++ b/components/signin/core/browser/signin_metrics.h
@@ -159,6 +159,7 @@
   ACCESS_POINT_SAVE_CARD_BUBBLE = 24,
   ACCESS_POINT_MANAGE_CARDS_BUBBLE = 25,
   ACCESS_POINT_MACHINE_LOGON = 26,
+  ACCESS_POINT_GOOGLE_SERVICES_SETTINGS = 27,
   ACCESS_POINT_MAX,  // This must be last.
 };
 
diff --git a/components/signin/core/browser/signin_metrics_unittest.cc b/components/signin/core/browser/signin_metrics_unittest.cc
index 72ed284..ec4cb74 100644
--- a/components/signin/core/browser/signin_metrics_unittest.cc
+++ b/components/signin/core/browser/signin_metrics_unittest.cc
@@ -106,6 +106,8 @@
         return "ManageCardsBubble";
       case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
         return "MachineLogon";
+      case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
+        return "GoogleServicesSettings";
       case AccessPoint::ACCESS_POINT_MAX:
         NOTREACHED();
         return "";
diff --git a/components/sync/driver/sync_auth_util.cc b/components/sync/driver/sync_auth_util.cc
index 6e6b6df..df0bc53 100644
--- a/components/sync/driver/sync_auth_util.cc
+++ b/components/sync/driver/sync_auth_util.cc
@@ -31,7 +31,7 @@
     // Check if there is a content area signed-in account, and we have a refresh
     // token for it.
     std::vector<AccountInfo> cookie_accounts =
-        identity_manager->GetAccountsInCookieJar().accounts;
+        identity_manager->GetAccountsInCookieJar().signed_in_accounts;
     if (!cookie_accounts.empty() &&
         identity_manager->HasAccountWithRefreshToken(
             cookie_accounts[0].account_id)) {
diff --git a/components/sync/driver/sync_session_durations_metrics_recorder.cc b/components/sync/driver/sync_session_durations_metrics_recorder.cc
index fec721a..b1e36697 100644
--- a/components/sync/driver/sync_session_durations_metrics_recorder.cc
+++ b/components/sync/driver/sync_session_durations_metrics_recorder.cc
@@ -76,22 +76,26 @@
     return;
   }
 
-  base::TimeDelta inactivity_at_session_end =
-      total_session_timer_->Elapsed() - session_length;
-  LogSigninDuration(SubtractInactiveTime(signin_session_timer_->Elapsed(),
-                                         inactivity_at_session_end));
-  LogSyncAndAccountDuration(SubtractInactiveTime(
-      sync_account_session_timer_->Elapsed(), inactivity_at_session_end));
+  base::TimeDelta total_session_time = total_session_timer_->Elapsed();
+  base::TimeDelta signin_session_time = signin_session_timer_->Elapsed();
+  base::TimeDelta sync_account_session_time_ =
+      sync_account_session_timer_->Elapsed();
   total_session_timer_.reset();
   signin_session_timer_.reset();
   sync_account_session_timer_.reset();
+
+  base::TimeDelta total_inactivity_time = total_session_time - session_length;
+  LogSigninDuration(
+      SubtractInactiveTime(signin_session_time, total_inactivity_time));
+  LogSyncAndAccountDuration(
+      SubtractInactiveTime(sync_account_session_time_, total_inactivity_time));
 }
 
 void SyncSessionDurationsMetricsRecorder::OnAccountsInCookieUpdated(
     const identity::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
     const GoogleServiceAuthError& error) {
   DVLOG(1) << "Cookie state change. accounts: "
-           << accounts_in_cookie_jar_info.accounts.size()
+           << accounts_in_cookie_jar_info.signed_in_accounts.size()
            << " fresh: " << accounts_in_cookie_jar_info.accounts_are_fresh
            << " err: " << error.ToString();
 
@@ -103,7 +107,7 @@
   }
 
   DCHECK(accounts_in_cookie_jar_info.accounts_are_fresh);
-  if (accounts_in_cookie_jar_info.accounts.empty()) {
+  if (accounts_in_cookie_jar_info.signed_in_accounts.empty()) {
     // No signed in account.
     if (signin_status_ == FeatureState::ON && signin_session_timer_) {
       LogSigninDuration(signin_session_timer_->Elapsed());
diff --git a/components/viz/host/host_gpu_memory_buffer_manager.h b/components/viz/host/host_gpu_memory_buffer_manager.h
index c5d5baa..7cc3a469 100644
--- a/components/viz/host/host_gpu_memory_buffer_manager.h
+++ b/components/viz/host/host_gpu_memory_buffer_manager.h
@@ -95,10 +95,9 @@
     gpu::SurfaceHandle surface_handle;
     base::OnceCallback<void(gfx::GpuMemoryBufferHandle)> callback;
   };
-  using PendingBuffers =
-      std::unordered_map<gfx::GpuMemoryBufferId,
-                         PendingBufferInfo,
-                         BASE_HASH_NAMESPACE::hash<gfx::GpuMemoryBufferId>>;
+  using PendingBuffers = std::unordered_map<gfx::GpuMemoryBufferId,
+                                            PendingBufferInfo,
+                                            std::hash<gfx::GpuMemoryBufferId>>;
 
   struct AllocatedBufferInfo {
     AllocatedBufferInfo();
@@ -111,7 +110,7 @@
   using AllocatedBuffers =
       std::unordered_map<gfx::GpuMemoryBufferId,
                          AllocatedBufferInfo,
-                         BASE_HASH_NAMESPACE::hash<gfx::GpuMemoryBufferId>>;
+                         std::hash<gfx::GpuMemoryBufferId>>;
 
   mojom::GpuService* GetGpuService();
 
diff --git a/content/browser/android/content_url_loader_factory.cc b/content/browser/android/content_url_loader_factory.cc
index 546f6f3..60417bf 100644
--- a/content/browser/android/content_url_loader_factory.cc
+++ b/content/browser/android/content_url_loader_factory.cc
@@ -97,11 +97,9 @@
   }
 
   // network::mojom::URLLoader:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override {}
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override {}
   void ProceedWithResponse() override {}
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override {}
diff --git a/content/browser/appcache/appcache_subresource_url_factory.cc b/content/browser/appcache/appcache_subresource_url_factory.cc
index 95ee02d..b4d0722 100644
--- a/content/browser/appcache/appcache_subresource_url_factory.cc
+++ b/content/browser/appcache/appcache_subresource_url_factory.cc
@@ -127,17 +127,16 @@
 
   // network::mojom::URLLoader implementation
   // Called by the remote client in the renderer.
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override {
-    DCHECK(!modified_request_headers.has_value())
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override {
+    DCHECK(removed_headers.empty() && modified_headers.IsEmpty())
         << "Redirect with modified headers was not supported yet. "
            "crbug.com/845683";
     if (!handler_) {
-      network_loader_->FollowRedirect(base::nullopt, base::nullopt,
-                                      base::nullopt);
+      network_loader_->FollowRedirect({} /* removed_headers */,
+                                      {} /* modified_headers */,
+                                      base::nullopt /* new_url */);
       return;
     }
     DCHECK(network_loader_);
@@ -156,8 +155,9 @@
     if (handler) {
       CreateAndStartAppCacheLoader(std::move(handler));
     } else {
-      network_loader_->FollowRedirect(base::nullopt, base::nullopt,
-                                      base::nullopt);
+      network_loader_->FollowRedirect({} /* removed_headers */,
+                                      {} /* modified_headers */,
+                                      base::nullopt /* new_url */);
     }
   }
 
diff --git a/content/browser/appcache/appcache_url_loader_job.cc b/content/browser/appcache/appcache_url_loader_job.cc
index 904a18a..ef679182 100644
--- a/content/browser/appcache/appcache_url_loader_job.cc
+++ b/content/browser/appcache/appcache_url_loader_job.cc
@@ -106,9 +106,8 @@
 }
 
 void AppCacheURLLoaderJob::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+    const std::vector<std::string>& modified_headers,
+    const net::HttpRequestHeaders& removed_headers,
     const base::Optional<GURL>& new_url) {
   NOTREACHED() << "appcache never produces redirects";
 }
diff --git a/content/browser/appcache/appcache_url_loader_job.h b/content/browser/appcache/appcache_url_loader_job.h
index 0be2d683..cbac6ce 100644
--- a/content/browser/appcache/appcache_url_loader_job.h
+++ b/content/browser/appcache/appcache_url_loader_job.h
@@ -56,11 +56,9 @@
   base::WeakPtr<AppCacheURLLoaderJob> GetDerivedWeakPtr();
 
   // network::mojom::URLLoader implementation:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override;
diff --git a/content/browser/background_fetch/background_fetch_registration_notifier.cc b/content/browser/background_fetch/background_fetch_registration_notifier.cc
index a98b02c..79445896 100644
--- a/content/browser/background_fetch/background_fetch_registration_notifier.cc
+++ b/content/browser/background_fetch/background_fetch_registration_notifier.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/metrics/histogram_macros.h"
 #include "content/common/background_fetch/background_fetch_types.h"
 #include "content/public/common/content_switches.h"
 
@@ -43,6 +44,18 @@
 
 void BackgroundFetchRegistrationNotifier::NotifyRecordsUnavailable(
     const std::string& unique_id) {
+  auto iter = num_requests_and_updates_.find(unique_id);
+  if (iter == num_requests_and_updates_.end())
+    return;
+
+  // Record the percentage of requests we've sent updates for.
+  int num_updates_sent = iter->second.first;
+  int num_total_requests = iter->second.second;
+  UMA_HISTOGRAM_PERCENTAGE(
+      "BackgroundFetch.PercentOfRequestsForWhichUpdatesAreSent",
+      static_cast<int>(num_updates_sent * 100.0 / num_total_requests));
+  num_requests_and_updates_.erase(iter);
+
   for (auto it = observers_.begin(); it != observers_.end();) {
     if (it->first != unique_id) {
       it++;
@@ -86,6 +99,11 @@
         BackgroundFetchSettledFetch::CloneRequest(request),
         BackgroundFetchSettledFetch::CloneResponse(response));
   }
+
+  auto iter = num_requests_and_updates_.find(unique_id);
+  if (iter == num_requests_and_updates_.end())
+    return;
+  iter->second.first++;
 }
 
 void BackgroundFetchRegistrationNotifier::OnConnectionError(
@@ -98,4 +116,12 @@
                 });
 }
 
+void BackgroundFetchRegistrationNotifier::NoteTotalRequests(
+    const std::string& unique_id,
+    int num_total_requests) {
+  DCHECK(!num_requests_and_updates_.count(unique_id));
+  num_requests_and_updates_[unique_id] = {/* total_updates_sent= */ 0,
+                                          num_total_requests};
+}
+
 }  // namespace content
diff --git a/content/browser/background_fetch/background_fetch_registration_notifier.h b/content/browser/background_fetch/background_fetch_registration_notifier.h
index 7cfee63..29fb5a76 100644
--- a/content/browser/background_fetch/background_fetch_registration_notifier.h
+++ b/content/browser/background_fetch/background_fetch_registration_notifier.h
@@ -51,6 +51,8 @@
   // |observers_| start getting updates about any requests with this URL.
   void AddObservedUrl(const std::string& unique_id, const GURL& url);
 
+  void NoteTotalRequests(const std::string& unique_id, int num_total_requests);
+
   base::WeakPtr<BackgroundFetchRegistrationNotifier> GetWeakPtr() {
     return weak_factory_.GetWeakPtr();
   }
@@ -70,6 +72,11 @@
   // URLs the observers care about, indexed by the unique_id of the observer.
   std::map<std::string, std::set<GURL>> observed_urls_;
 
+  // For the observer identified by |unique_id|, this stores the number of its
+  // requests, and the number for which updates are sent across the mojo pipe.
+  // This is used for UMA recording.
+  std::map<std::string, std::pair<int, int>> num_requests_and_updates_;
+
   base::WeakPtrFactory<BackgroundFetchRegistrationNotifier> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(BackgroundFetchRegistrationNotifier);
diff --git a/content/browser/background_fetch/background_fetch_registration_notifier_unittest.cc b/content/browser/background_fetch/background_fetch_registration_notifier_unittest.cc
index 5c7ba2d..0e2ac83 100644
--- a/content/browser/background_fetch/background_fetch_registration_notifier_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_registration_notifier_unittest.cc
@@ -267,6 +267,7 @@
 TEST_F(BackgroundFetchRegistrationNotifierTest, NotifyRecordsUnavailable) {
   auto observer = std::make_unique<TestRegistrationObserver>();
 
+  notifier_->NoteTotalRequests(kPrimaryUniqueId, /* num_total_requests= */ 1);
   notifier_->AddObserver(kPrimaryUniqueId, observer->GetPtr());
   ASSERT_TRUE(observer->records_available());
 
@@ -278,6 +279,7 @@
   auto observer = std::make_unique<TestRegistrationObserver>();
 
   notifier_->AddObserver(kPrimaryUniqueId, observer->GetPtr());
+  notifier_->NoteTotalRequests(kPrimaryUniqueId, /* num_total_requests= */ 1);
 
   // No observed URLs. Observers shouldn't have been notified.
   ASSERT_EQ(observer->completed_requests().size(), 0u);
diff --git a/content/browser/background_fetch/background_fetch_scheduler.cc b/content/browser/background_fetch/background_fetch_scheduler.cc
index d2eb335f..1235401 100644
--- a/content/browser/background_fetch/background_fetch_scheduler.cc
+++ b/content/browser/background_fetch/background_fetch_scheduler.cc
@@ -228,6 +228,10 @@
     int num_requests,
     bool start_paused) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  registration_notifier_->NoteTotalRequests(registration_id.unique_id(),
+                                            num_requests);
+
   auto controller = CreateInitializedController(
       registration_id, registration, std::move(options), icon,
       /* completed_requests= */ 0, num_requests,
diff --git a/content/browser/browsing_data/conditional_cache_deletion_helper_browsertest.cc b/content/browser/browsing_data/conditional_cache_deletion_helper_browsertest.cc
index 7492aef..54f5aed 100644
--- a/content/browser/browsing_data/conditional_cache_deletion_helper_browsertest.cc
+++ b/content/browser/browsing_data/conditional_cache_deletion_helper_browsertest.cc
@@ -184,17 +184,9 @@
 // Note: This test depends on the timing in cache backends and can be flaky
 // if those backends are slow.
 //
-// Flakily timing out on Mac 10.11 (crbug.com/646119) and flakily
-// failing on Linux/ChromeOS (crbug.com/624836)
-// --> Switched to tiny_timeout and enabled the test on all platforms to check
-//     if it will be more stable now.
-#if false
-#define MAYBE_TimeAndURL DISABLED_TimeAndURL
-#else
-#define MAYBE_TimeAndURL TimeAndURL
-#endif
-IN_PROC_BROWSER_TEST_F(ConditionalCacheDeletionHelperBrowserTest,
-                       MAYBE_TimeAndURL) {
+// It previously flaked on Mac 10.11 (crbug.com/646119) and on Linux/ChromeOS
+// (crbug.com/624836) but it seems to be stable now.
+IN_PROC_BROWSER_TEST_F(ConditionalCacheDeletionHelperBrowserTest, TimeAndURL) {
   // https://crbug.com/911171: this test depends on the timing of the cache,
   // which changes if it's running out-of-process.
   if (base::FeatureList::IsEnabled(network::features::kNetworkService))
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.cc b/content/browser/devtools/devtools_url_loader_interceptor.cc
index 0a9d90f..ebe4d8b 100644
--- a/content/browser/devtools/devtools_url_loader_interceptor.cc
+++ b/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -298,10 +298,9 @@
   }
 
   // network::mojom::URLLoader methods
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>& removed_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override;
@@ -878,7 +877,7 @@
     } else {
       // TODO(caseq): report error if other modifications are present.
       state_ = State::kRequestSent;
-      loader_->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+      loader_->FollowRedirect({}, {}, base::nullopt);
       return Response::OK();
     }
   }
@@ -1285,13 +1284,13 @@
 
 // URLLoader methods
 void InterceptionJob::FollowRedirect(
-    const base::Optional<std::vector<std::string>>& removed_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
   // TODO(arthursonzogni, juncai): This seems to be correctly implemented, but
   // not used nor tested so far. Add tests and remove this DCHECK to support
   // this feature if needed. See https://crbug.com/845683.
-  DCHECK(!removed_headers && !modified_headers)
+  DCHECK(removed_headers.empty() && modified_headers.IsEmpty())
       << "Redirect with removed or modified headers is not supported yet. See "
          "https://crbug.com/845683";
   DCHECK(!new_url.has_value()) << "Redirect with modified url was not "
diff --git a/content/browser/file_url_loader_factory.cc b/content/browser/file_url_loader_factory.cc
index bfcd845..e3eed3d 100644
--- a/content/browser/file_url_loader_factory.cc
+++ b/content/browser/file_url_loader_factory.cc
@@ -138,11 +138,9 @@
   }
 
   // network::mojom::URLLoader:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override {}
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override {}
   void ProceedWithResponse() override { NOTREACHED(); }
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override {}
@@ -350,11 +348,11 @@
   }
 
   // network::mojom::URLLoader:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override {
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override {
+    // |removed_headers| and |modified_headers| are unused. It doesn't make
+    // sense for files. The FileURLLoader can redirect only to another file.
     std::unique_ptr<RedirectData> redirect_data = std::move(redirect_data_);
     if (redirect_data->is_directory) {
       FileURLDirectoryLoader::CreateAndStart(
diff --git a/content/browser/fileapi/file_system_url_loader_factory.cc b/content/browser/fileapi/file_system_url_loader_factory.cc
index bfc9a1a..05c3a79 100644
--- a/content/browser/fileapi/file_system_url_loader_factory.cc
+++ b/content/browser/fileapi/file_system_url_loader_factory.cc
@@ -95,11 +95,9 @@
       : binding_(this), params_(std::move(params)) {}
 
   // network::mojom::URLLoader:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override {}
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override {}
   void ProceedWithResponse() override {}
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override {}
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index e460d996..b42122b 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -2054,6 +2054,7 @@
     const Referrer& referrer,
     ui::PageTransition page_transition,
     bool should_replace_current_entry,
+    NavigationDownloadPolicy download_policy,
     const std::string& method,
     scoped_refptr<network::ResourceRequestBody> post_body,
     const std::string& extra_headers,
@@ -2163,7 +2164,7 @@
       CreateNavigationRequestFromLoadParams(
           render_frame_host->frame_tree_node(), params, override_user_agent,
           should_replace_current_entry, false /* has_user_gesture */,
-          ReloadType::NONE, *entry, frame_entry.get());
+          download_policy, ReloadType::NONE, *entry, frame_entry.get());
 
   if (!request)
     return;
@@ -2637,8 +2638,8 @@
   std::unique_ptr<NavigationRequest> request =
       CreateNavigationRequestFromLoadParams(
           node, params, override_user_agent, should_replace_current_entry,
-          has_user_gesture, reload_type, *pending_entry_,
-          pending_entry_->GetFrameEntry(node));
+          has_user_gesture, NavigationDownloadPolicy::kAllow, reload_type,
+          *pending_entry_, pending_entry_->GetFrameEntry(node));
 
   // If the navigation couldn't start, return immediately and discard the
   // pending NavigationEntry.
@@ -2782,6 +2783,7 @@
     bool override_user_agent,
     bool should_replace_current_entry,
     bool has_user_gesture,
+    NavigationDownloadPolicy download_policy,
     ReloadType reload_type,
     const NavigationEntryImpl& entry,
     FrameNavigationEntry* frame_entry) {
@@ -2866,9 +2868,13 @@
   // Create the NavigationParams based on |params|.
 
   bool is_view_source_mode = virtual_url.SchemeIs(kViewSourceScheme);
-  NavigationDownloadPolicy download_policy =
-      is_view_source_mode ? NavigationDownloadPolicy::kDisallowViewSource
-                          : NavigationDownloadPolicy::kAllow;
+
+  // Update |download_policy| if the virtual URL is view-source. Why do this
+  // now? Possibly the URL could be rewritten to a view-source via some URL
+  // handler.
+  if (is_view_source_mode)
+    download_policy = NavigationDownloadPolicy::kDisallowViewSource;
+
   const GURL& history_url_for_data_url =
       params.base_url_for_data_url.is_empty() ? GURL() : virtual_url;
   CommonNavigationParams common_params(
diff --git a/content/browser/frame_host/navigation_controller_impl.h b/content/browser/frame_host/navigation_controller_impl.h
index 0023690..0cdd5ed 100644
--- a/content/browser/frame_host/navigation_controller_impl.h
+++ b/content/browser/frame_host/navigation_controller_impl.h
@@ -113,6 +113,7 @@
       const Referrer& referrer,
       ui::PageTransition page_transition,
       bool should_replace_current_entry,
+      NavigationDownloadPolicy download_policy,
       const std::string& method,
       scoped_refptr<network::ResourceRequestBody> post_body,
       const std::string& extra_headers,
@@ -317,6 +318,7 @@
       bool override_user_agent,
       bool should_replace_current_entry,
       bool has_user_gesture,
+      NavigationDownloadPolicy download_policy,
       ReloadType reload_type,
       const NavigationEntryImpl& entry,
       FrameNavigationEntry* frame_entry);
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index df12172..98cdf3a 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -5232,7 +5232,8 @@
       subframe_node->current_frame_host(), kSrcDoc, url::Origin::Create(kUrl2),
       true /* is_renderer_initiated */, main_test_rfh()->GetSiteInstance(),
       Referrer(), ui::PAGE_TRANSITION_LINK,
-      false /* should_replace_current_entry */, "GET", nullptr, "", nullptr);
+      false /* should_replace_current_entry */,
+      NavigationDownloadPolicy::kAllow, "GET", nullptr, "", nullptr);
 
   // Clean up the handler.
   BrowserURLHandlerImpl::GetInstance()->SetFixupHandlerForTesting(nullptr);
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc
index 2cd6997f..abbc4d8 100644
--- a/content/browser/frame_host/navigation_handle_impl.cc
+++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -463,6 +463,10 @@
   return ssl_info_;
 }
 
+bool NavigationHandleImpl::IsWaitingToCommit() {
+  return state_ == READY_TO_COMMIT;
+}
+
 bool NavigationHandleImpl::HasCommitted() {
   return state_ == DID_COMMIT || state_ == DID_COMMIT_ERROR_PAGE;
 }
@@ -527,37 +531,6 @@
 }
 
 NavigationThrottle::ThrottleCheckResult
-NavigationHandleImpl::CallWillRedirectRequestForTesting(
-    const GURL& new_url,
-    bool new_method_is_post,
-    const GURL& new_referrer_url,
-    bool new_is_external_protocol) {
-  NavigationThrottle::ThrottleCheckResult result = NavigationThrottle::DEFER;
-  WillRedirectRequest(new_url, new_method_is_post ? "POST" : "GET",
-                      new_referrer_url, new_is_external_protocol,
-                      scoped_refptr<net::HttpResponseHeaders>(),
-                      net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN, nullptr,
-                      base::Bind(&UpdateThrottleCheckResult, &result));
-
-  // Reset the callback to ensure it will not be called later.
-  complete_callback_.Reset();
-  return result;
-}
-
-NavigationThrottle::ThrottleCheckResult
-NavigationHandleImpl::CallWillFailRequestForTesting(
-    RenderFrameHost* render_frame_host,
-    base::Optional<net::SSLInfo> ssl_info) {
-  NavigationThrottle::ThrottleCheckResult result = NavigationThrottle::DEFER;
-  WillFailRequest(static_cast<RenderFrameHostImpl*>(render_frame_host),
-                  ssl_info, base::Bind(&UpdateThrottleCheckResult, &result));
-
-  // Reset the callback to ensure it will not be called later.
-  complete_callback_.Reset();
-  return result;
-}
-
-NavigationThrottle::ThrottleCheckResult
 NavigationHandleImpl::CallWillProcessResponseForTesting(
     RenderFrameHost* render_frame_host,
     const std::string& raw_response_headers,
@@ -581,25 +554,6 @@
   return result;
 }
 
-void NavigationHandleImpl::CallDidCommitNavigationForTesting(const GURL& url) {
-  FrameHostMsg_DidCommitProvisionalLoad_Params params;
-
-  params.nav_entry_id = 1;
-  params.url = url;
-  params.referrer = content::Referrer();
-  params.transition = ui::PAGE_TRANSITION_TYPED;
-  params.redirects = std::vector<GURL>();
-  params.should_update_history = false;
-  params.did_create_new_entry = false;
-  params.gesture = NavigationGestureUser;
-  params.method = "GET";
-  params.page_state = PageState::CreateFromURL(url);
-  params.contents_mime_type = std::string("text/html");
-
-  DidCommitNavigation(params, true, false, GURL(), NAVIGATION_TYPE_NEW_PAGE,
-                      render_frame_host_);
-}
-
 void NavigationHandleImpl::CallResumeForTesting() {
   ResumeInternal();
 }
diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h
index d3de646..684c326 100644
--- a/content/browser/frame_host/navigation_handle_impl.h
+++ b/content/browser/frame_host/navigation_handle_impl.h
@@ -139,23 +139,6 @@
   const net::SSLInfo& GetSSLInfo() override;
   void RegisterThrottleForTesting(
       std::unique_ptr<NavigationThrottle> navigation_throttle) override;
-  NavigationThrottle::ThrottleCheckResult CallWillStartRequestForTesting()
-      override;
-  NavigationThrottle::ThrottleCheckResult CallWillRedirectRequestForTesting(
-      const GURL& new_url,
-      bool new_method_is_post,
-      const GURL& new_referrer_url,
-      bool new_is_external_protocol) override;
-  NavigationThrottle::ThrottleCheckResult CallWillFailRequestForTesting(
-      RenderFrameHost* render_frame_host,
-      base::Optional<net::SSLInfo> ssl_info) override;
-  NavigationThrottle::ThrottleCheckResult CallWillProcessResponseForTesting(
-      RenderFrameHost* render_frame_host,
-      const std::string& raw_response_header,
-      bool was_cached,
-      const net::ProxyServer& proxy_server) override;
-  void CallDidCommitNavigationForTesting(const GURL& url) override;
-  void CallResumeForTesting() override;
   bool IsDeferredForTesting() override;
   bool WasStartedFromContextMenu() const override;
   const GURL& GetSearchableFormURL() override;
@@ -185,6 +168,20 @@
   void CancelDeferredNavigation(NavigationThrottle* cancelling_throttle,
                                 NavigationThrottle::ThrottleCheckResult result);
 
+  // Simulates various calls on the NavigationHandle for testing.
+  // DEPRECATED: use NavigationSimulator to simulate a full navigation, or
+  // MockNavigationHandle.
+  NavigationThrottle::ThrottleCheckResult CallWillStartRequestForTesting();
+  NavigationThrottle::ThrottleCheckResult CallWillProcessResponseForTesting(
+      RenderFrameHost* render_frame_host,
+      const std::string& raw_response_header,
+      bool was_cached,
+      const net::ProxyServer& proxy_server);
+
+  // Simulates the navigation resuming. Most callers should just let the
+  // deferring NavigationThrottle do the resuming.
+  void CallResumeForTesting();
+
   NavigationData* GetNavigationData() override;
   void RegisterSubresourceOverride(
       mojom::TransferrableURLLoaderPtr transferrable_loader) override;
@@ -386,6 +383,11 @@
     return GetDeferringThrottle();
   }
 
+  // Whether the navigation was sent to be committed in a renderer by the
+  // RenderFrameHost. This can either be for the commit of a successful
+  // navigation or an error page.
+  bool IsWaitingToCommit();
+
   // Sets the READY_TO_COMMIT -> DID_COMMIT timeout.  Resets the timeout to the
   // default value if |timeout| is zero.
   static void SetCommitTimeoutForTesting(const base::TimeDelta& timeout);
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 357f1cc..816a38a7 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -163,7 +163,7 @@
 // blink::FrameFetchContext::addAdditionalRequestHeaders.
 void AddAdditionalRequestHeaders(
     net::HttpRequestHeaders* headers,
-    std::unique_ptr<net::HttpRequestHeaders> embedder_additional_headers,
+    net::HttpRequestHeaders embedder_additional_headers,
     const GURL& url,
     FrameMsg_Navigate_Type::Value navigation_type,
     BrowserContext* browser_context,
@@ -189,8 +189,7 @@
   }
 
   // Attach additional request headers specified by embedder.
-  if (embedder_additional_headers)
-    headers->MergeFrom(*(embedder_additional_headers.get()));
+  headers->MergeFrom(std::move(embedder_additional_headers));
 
   // Tack an 'Upgrade-Insecure-Requests' header to outgoing navigational
   // requests, as described in
@@ -482,7 +481,8 @@
       request_navigation_client_ = mojom::NavigationClientAssociatedPtr();
       request_navigation_client_.Bind(std::move(navigation_client));
       // Binds the OnAbort callback
-      request_navigation_client_.set_connection_error_handler(
+      HandleInterfaceDisconnection(
+          &request_navigation_client_,
           base::BindOnce(&NavigationRequest::OnRendererAbortedNavigation,
                          base::Unretained(this)));
       associated_site_instance_id_ = source_site_instance_->GetId();
@@ -517,12 +517,12 @@
         frame_tree_node_->navigator()->GetDelegate()->GetUserAgentOverride();
   }
 
-  std::unique_ptr<net::HttpRequestHeaders> embedder_additional_headers;
-  int additional_load_flags = 0;
   net::HttpRequestHeaders headers;
   // Only add specific headers when creating a NavigationRequest before the
   // network request is made, not at commit time.
   if (!is_for_commit) {
+    int additional_load_flags = 0;
+    net::HttpRequestHeaders embedder_additional_headers;
     GetContentClient()->browser()->NavigationRequestStarted(
         frame_tree_node->frame_tree_node_id(), common_params_.url,
         &embedder_additional_headers, &additional_load_flags);
@@ -818,7 +818,9 @@
 mojom::NavigationClient* NavigationRequest::GetCommitNavigationClient() {
   if (commit_navigation_client_ && commit_navigation_client_.is_bound())
     return commit_navigation_client_.get();
-  return nullptr;
+  commit_navigation_client_ = navigation_handle_->GetRenderFrameHost()
+                                  ->GetNavigationClientFromInterfaceProvider();
+  return commit_navigation_client_.get();
 }
 
 void NavigationRequest::OnRequestRedirected(
@@ -1551,12 +1553,13 @@
 
   devtools_instrumentation::OnNavigationRequestWillBeSent(*this);
 
-  base::Optional<net::HttpRequestHeaders> embedder_additional_headers;
+  net::HttpRequestHeaders embedder_additional_headers;
+  std::vector<std::string> embedder_removed_headers;
   GetContentClient()->browser()->NavigationRequestRedirected(
       frame_tree_node_->frame_tree_node_id(), common_params_.url,
       &embedder_additional_headers);
 
-  loader_->FollowRedirect(base::nullopt,
+  loader_->FollowRedirect(std::move(embedder_removed_headers),
                           std::move(embedder_additional_headers));
 }
 
@@ -1715,18 +1718,14 @@
   frame_tree_node_->TransferNavigationRequestOwnership(render_frame_host);
   if (IsPerNavigationMojoInterfaceEnabled() && request_navigation_client_ &&
       request_navigation_client_.is_bound()) {
-    // Two cases are possible here:
-    // Either we have a same-site navigation in which case the navigation
-    // request needs to be canceled in the RFH, so we need to rebind the handler
-    // to a post-ReadyToCommit handler.
-    // TODO(ahemery): Implement this second abort handler.
-    // Or this navigation is cross-site: the original document should no longer
-    // be able to cancel it.
-    IgnorePipeDisconnection();
     if (associated_site_instance_id_ ==
         render_frame_host->GetSiteInstance()->GetId()) {
       // Reuse the request NavigationClient for commit.
       commit_navigation_client_ = std::move(request_navigation_client_);
+    } else {
+      IgnoreInterfaceDisconnection();
+      // This navigation is cross-site: the original document should no longer
+      // be able to cancel it.
     }
     associated_site_instance_id_.reset();
   }
@@ -1765,18 +1764,14 @@
   frame_tree_node_->TransferNavigationRequestOwnership(render_frame_host);
   if (IsPerNavigationMojoInterfaceEnabled() && request_navigation_client_ &&
       request_navigation_client_.is_bound()) {
-    // Two cases are possible here:
-    // Either we have a same-site navigation in which case the navigation
-    // request needs to be canceled in the RFH, so we need to rebind the handler
-    // to a post-ReadyToCommit handler.
-    // TODO(ahemery): Implement this second abort handler.
-    // Or this navigation is cross-site: the original document should no longer
-    // be able to cancel it.
-    IgnorePipeDisconnection();
     if (associated_site_instance_id_ ==
         render_frame_host->GetSiteInstance()->GetId()) {
       // Reuse the request NavigationClient for commit.
       commit_navigation_client_ = std::move(request_navigation_client_);
+    } else {
+      // This navigation is cross-site: the original document should no longer
+      // be able to cancel it.
+      IgnoreInterfaceDisconnection();
     }
     associated_site_instance_id_.reset();
   }
@@ -1983,12 +1978,22 @@
 }
 
 void NavigationRequest::OnRendererAbortedNavigation() {
-  frame_tree_node_->navigator()->CancelNavigation(frame_tree_node_, false);
+  if (navigation_handle_->IsWaitingToCommit()) {
+    navigation_handle_->GetRenderFrameHost()->NavigationRequestCancelled(this);
+  } else {
+    frame_tree_node_->navigator()->CancelNavigation(frame_tree_node_, false);
+  }
 
   // Do not add code after this, NavigationRequest has been destroyed.
 }
 
-void NavigationRequest::IgnorePipeDisconnection() {
+void NavigationRequest::HandleInterfaceDisconnection(
+    mojom::NavigationClientAssociatedPtr* navigation_client,
+    base::OnceClosure error_handler) {
+  navigation_client->set_connection_error_handler(std::move(error_handler));
+}
+
+void NavigationRequest::IgnoreInterfaceDisconnection() {
   return request_navigation_client_.set_connection_error_handler(
       base::DoNothing());
 }
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index ee33d80..f3227daa 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -221,9 +221,8 @@
   void RegisterSubresourceOverride(
       mojom::TransferrableURLLoaderPtr transferrable_loader);
 
-  // Returns the NavigationClient held by this navigation request that is ready
-  // to commit, or nullptr if there isn't any.
-  // Only used with PerNavigationMojoInterface enabled.
+  // Lazily initializes and returns the mojo::NavigationClient interface used
+  // for commit. Only used with PerNavigationMojoInterface enabled.
   mojom::NavigationClient* GetCommitNavigationClient();
 
  private:
@@ -356,12 +355,18 @@
   // Only used with PerNavigationMojoInterface enabled.
   void OnRendererAbortedNavigation();
 
-  // When called, this NavigationRequest will no longer interpret the pipe
+  // Binds the given error_handler to be called when an interface disconnection
+  // happens on the renderer side.
+  // Only used with PerNavigationMojoInterface enabled.
+  void HandleInterfaceDisconnection(mojom::NavigationClientAssociatedPtr*,
+                                    base::OnceClosure error_handler);
+
+  // When called, this NavigationRequest will no longer interpret the interface
   // disconnection on the renderer side as an AbortNavigation.
   // TODO(ahemery): remove this function when NavigationRequest properly handles
-  // pipe disconnection in all cases. Only used with PerNavigationMojoInterface
-  // enabled.
-  void IgnorePipeDisconnection();
+  // interface disconnection in all cases.
+  // Only used with PerNavigationMojoInterface enabled.
+  void IgnoreInterfaceDisconnection();
 
   FrameTreeNode* frame_tree_node_;
 
diff --git a/content/browser/frame_host/navigator.h b/content/browser/frame_host/navigator.h
index 4d2d481..dae4b8d 100644
--- a/content/browser/frame_host/navigator.h
+++ b/content/browser/frame_host/navigator.h
@@ -127,6 +127,7 @@
       const Referrer& referrer,
       ui::PageTransition page_transition,
       bool should_replace_current_entry,
+      NavigationDownloadPolicy download_policy,
       const std::string& method,
       scoped_refptr<network::ResourceRequestBody> post_body,
       const std::string& extra_headers,
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index dbb4903..0937708e 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -474,6 +474,7 @@
     const Referrer& referrer,
     ui::PageTransition page_transition,
     bool should_replace_current_entry,
+    NavigationDownloadPolicy download_policy,
     const std::string& method,
     scoped_refptr<network::ResourceRequestBody> post_body,
     const std::string& extra_headers,
@@ -525,8 +526,8 @@
   controller_->NavigateFromFrameProxy(
       render_frame_host, url, initiator_origin, is_renderer_initiated,
       source_site_instance, referrer_to_use, page_transition,
-      should_replace_current_entry, method, post_body, extra_headers,
-      std::move(blob_url_loader_factory));
+      should_replace_current_entry, download_policy, method, post_body,
+      extra_headers, std::move(blob_url_loader_factory));
 }
 
 void NavigatorImpl::OnBeforeUnloadACK(FrameTreeNode* frame_tree_node,
diff --git a/content/browser/frame_host/navigator_impl.h b/content/browser/frame_host/navigator_impl.h
index 3b729d1..6e6daea 100644
--- a/content/browser/frame_host/navigator_impl.h
+++ b/content/browser/frame_host/navigator_impl.h
@@ -80,6 +80,7 @@
       const Referrer& referrer,
       ui::PageTransition page_transition,
       bool should_replace_current_entry,
+      NavigationDownloadPolicy download_policy,
       const std::string& method,
       scoped_refptr<network::ResourceRequestBody> post_body,
       const std::string& extra_headers,
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index b2cc9269..be71bd75 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2381,6 +2381,8 @@
 
   if (web_ui())
     web_ui()->RenderFrameHostSwappingOut();
+
+  web_bluetooth_services_.clear();
 }
 
 void RenderFrameHostImpl::OnBeforeUnloadACK(
@@ -5341,6 +5343,20 @@
   return result;
 }
 
+mojom::NavigationClientAssociatedPtr
+RenderFrameHostImpl::GetNavigationClientFromInterfaceProvider() {
+  mojom::NavigationClientAssociatedPtr navigation_client_ptr;
+  GetRemoteAssociatedInterfaces()->GetInterface(&navigation_client_ptr);
+  return navigation_client_ptr;
+}
+
+void RenderFrameHostImpl::NavigationRequestCancelled(
+    NavigationRequest* navigation_request) {
+  OnCrossDocumentCommitProcessed(
+      navigation_request->navigation_handle()->GetNavigationId(),
+      blink::mojom::CommitResult::Aborted);
+}
+
 bool RenderFrameHostImpl::CreateNetworkServiceDefaultFactoryAndObserve(
     const base::Optional<url::Origin>& origin,
     network::mojom::URLLoaderFactoryRequest default_factory_request) {
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index e3543748..69564dcd 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -830,6 +830,16 @@
   void LeaveBackForwardCache();  // The document leaves the BackForwardCache.
   bool is_in_back_forward_cache() { return is_in_back_forward_cache_; }
 
+  // Request a new NavigationClient interface from the renderer and returns the
+  // ownership of the AssociatedPtr. This is intended for use by the
+  // NavigationRequest. Only used with PerNavigationMojoInterface enabled.
+  mojom::NavigationClientAssociatedPtr
+  GetNavigationClientFromInterfaceProvider();
+
+  // Called to signify the RenderFrameHostImpl that one of its ongoing
+  // NavigationRequest's has been cancelled.
+  void NavigationRequestCancelled(NavigationRequest* navigation_request);
+
  protected:
   friend class RenderFrameHostFactory;
 
diff --git a/content/browser/frame_host/render_frame_proxy_host.cc b/content/browser/frame_host/render_frame_proxy_host.cc
index 07e4c96..1b2ade81 100644
--- a/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/content/browser/frame_host/render_frame_proxy_host.cc
@@ -333,9 +333,9 @@
   frame_tree_node_->navigator()->NavigateFromFrameProxy(
       current_rfh, validated_url, params.initiator_origin, site_instance_.get(),
       params.referrer, ui::PAGE_TRANSITION_LINK,
-      params.should_replace_current_entry, params.uses_post ? "POST" : "GET",
-      params.resource_request_body, params.extra_headers,
-      std::move(blob_url_loader_factory));
+      params.should_replace_current_entry, params.download_policy,
+      params.uses_post ? "POST" : "GET", params.resource_request_body,
+      params.extra_headers, std::move(blob_url_loader_factory));
 }
 
 void RenderFrameProxyHost::OnCheckCompleted() {
diff --git a/content/browser/loader/cross_site_document_resource_handler.cc b/content/browser/loader/cross_site_document_resource_handler.cc
index 2bc9d8d..8f434fc 100644
--- a/content/browser/loader/cross_site_document_resource_handler.cc
+++ b/content/browser/loader/cross_site_document_resource_handler.cc
@@ -169,10 +169,9 @@
   }
 
   void ResumeForRedirect(
-      const base::Optional<std::vector<std::string>>& removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers)
-      override {
-    DCHECK(!modified_request_headers && !removed_request_headers)
+      const std::vector<std::string>& removed_headers,
+      const net::HttpRequestHeaders& modified_headers) override {
+    DCHECK(removed_headers.empty() && modified_headers.IsEmpty())
         << "Redirect with removed or modified headers is not supported yet. "
            "See https://crbug.com/845683";
     Resume();
diff --git a/content/browser/loader/detachable_resource_handler.cc b/content/browser/loader/detachable_resource_handler.cc
index b4ac539..e355a6d 100644
--- a/content/browser/loader/detachable_resource_handler.cc
+++ b/content/browser/loader/detachable_resource_handler.cc
@@ -39,9 +39,8 @@
   }
 
   void ResumeForRedirect(
-      const base::Optional<std::vector<std::string>>& removed_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_headers)
-      override {
+      const std::vector<std::string>& removed_headers,
+      const net::HttpRequestHeaders& modified_headers) override {
     MarkAsUsed();
     detachable_handler_->ResumeForRedirect(removed_headers, modified_headers);
   }
diff --git a/content/browser/loader/intercepting_resource_handler.cc b/content/browser/loader/intercepting_resource_handler.cc
index f2b71a3..8709a8d3 100644
--- a/content/browser/loader/intercepting_resource_handler.cc
+++ b/content/browser/loader/intercepting_resource_handler.cc
@@ -30,10 +30,9 @@
   }
 
   void ResumeForRedirect(
-      const base::Optional<std::vector<std::string>>& removed_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_headers)
-      override {
-    DCHECK(!removed_headers && !modified_headers)
+      const std::vector<std::string>& removed_headers,
+      const net::HttpRequestHeaders& modified_headers) override {
+    DCHECK(removed_headers.empty() && modified_headers.IsEmpty())
         << "Removing or modifying headers from the |new_handler| is not used "
            "and not supported. See https://crbug.com/845683.";
     Resume();
diff --git a/content/browser/loader/mime_sniffing_resource_handler.cc b/content/browser/loader/mime_sniffing_resource_handler.cc
index 9c74e93..29fa240 100644
--- a/content/browser/loader/mime_sniffing_resource_handler.cc
+++ b/content/browser/loader/mime_sniffing_resource_handler.cc
@@ -75,10 +75,9 @@
   }
 
   void ResumeForRedirect(
-      const base::Optional<std::vector<std::string>>& removed_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_headers)
-      override {
-    DCHECK(!removed_headers && !modified_headers)
+      const std::vector<std::string>& removed_headers,
+      const net::HttpRequestHeaders& modified_headers) override {
+    DCHECK(removed_headers.empty() && modified_headers.IsEmpty())
         << "Redirect with removed or modified headers is not used nor "
            "supported. See https://crbug.com/845683.";
     Resume();
diff --git a/content/browser/loader/mock_resource_loader.cc b/content/browser/loader/mock_resource_loader.cc
index c6f627f..066995d 100644
--- a/content/browser/loader/mock_resource_loader.cc
+++ b/content/browser/loader/mock_resource_loader.cc
@@ -26,10 +26,9 @@
   void Resume() override { mock_loader_->OnResume(); }
 
   void ResumeForRedirect(
-      const base::Optional<std::vector<std::string>>& removed_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_headers)
-      override {
-    DCHECK(!removed_headers && !modified_headers)
+      const std::vector<std::string>& removed_headers,
+      const net::HttpRequestHeaders& modified_headers) override {
+    DCHECK(removed_headers.empty() && modified_headers.IsEmpty())
         << "Redirect with removed or modified headers is not supported yet. "
            "See https://crbug.com/845683";
     Resume();
diff --git a/content/browser/loader/mojo_async_resource_handler.cc b/content/browser/loader/mojo_async_resource_handler.cc
index f50e583..0ecef929 100644
--- a/content/browser/loader/mojo_async_resource_handler.cc
+++ b/content/browser/loader/mojo_async_resource_handler.cc
@@ -385,8 +385,8 @@
 }
 
 void MojoAsyncResourceHandler::FollowRedirect(
-    const base::Optional<std::vector<std::string>>& removed_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
   if (new_url) {
     ReportBadMessage(
diff --git a/content/browser/loader/mojo_async_resource_handler.h b/content/browser/loader/mojo_async_resource_handler.h
index 38759f1..c3dc4722 100644
--- a/content/browser/loader/mojo_async_resource_handler.h
+++ b/content/browser/loader/mojo_async_resource_handler.h
@@ -84,10 +84,9 @@
       std::unique_ptr<ResourceController> controller) override;
 
   // network::mojom::URLLoader implementation:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>& removed_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override;
diff --git a/content/browser/loader/mojo_async_resource_handler_unittest.cc b/content/browser/loader/mojo_async_resource_handler_unittest.cc
index e2595330..6af5d5d 100644
--- a/content/browser/loader/mojo_async_resource_handler_unittest.cc
+++ b/content/browser/loader/mojo_async_resource_handler_unittest.cc
@@ -1209,7 +1209,7 @@
 
   ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
             mock_loader_->status());
-  handler_->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+  handler_->FollowRedirect({}, {}, base::nullopt);
   ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status());
 
   url_loader_client_.ClearHasReceivedRedirect();
@@ -1230,7 +1230,7 @@
 
   ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
             mock_loader_->status());
-  handler_->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+  handler_->FollowRedirect({}, {}, base::nullopt);
   ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status());
 
   // Give the final response.
@@ -1254,7 +1254,7 @@
 // redirect, despite the fact that no redirect has been received yet.
 TEST_P(MojoAsyncResourceHandlerWithAllocationSizeTest,
        MalformedFollowRedirectRequest) {
-  handler_->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+  handler_->FollowRedirect({}, {}, base::nullopt);
 
   EXPECT_TRUE(handler_->has_received_bad_message());
 }
diff --git a/content/browser/loader/navigation_url_loader.h b/content/browser/loader/navigation_url_loader.h
index 89b29a5..f744e9f 100644
--- a/content/browser/loader/navigation_url_loader.h
+++ b/content/browser/loader/navigation_url_loader.h
@@ -58,10 +58,9 @@
 
   // Called in response to OnRequestRedirected to continue processing the
   // request.
-  virtual void FollowRedirect(const base::Optional<std::vector<std::string>>&
-                                  to_be_removed_request_headers,
-                              const base::Optional<net::HttpRequestHeaders>&
-                                  modified_request_headers) = 0;
+  virtual void FollowRedirect(
+      const std::vector<std::string>& removed_headers,
+      const net::HttpRequestHeaders& modified_headers) = 0;
 
   // Called in response to OnResponseStarted to process the response.
   virtual void ProceedWithResponse() = 0;
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 70c543ba..e399585 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -1039,9 +1039,8 @@
     return factory;
   }
 
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>& removed_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_headers) {
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers) {
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
     DCHECK(!redirect_info_.new_url.is_empty());
     if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
@@ -1097,16 +1096,14 @@
       // header on when redirecting to the origins in the OriginList of
       // SignedHTTPExchangeAcceptHeader field trial, and need to remove it when
       // redirecting to out of the OriginList.
-      if (!url_loader_modified_headers_)
-        url_loader_modified_headers_ = net::HttpRequestHeaders();
       std::string accept_value = network::kFrameAcceptHeader;
       if (signed_exchange_utils::ShouldAdvertiseAcceptHeader(
               url::Origin::Create(resource_request_->url))) {
         DCHECK(!accept_value.empty());
         accept_value.append(kAcceptHeaderSignedExchangeSuffix);
       }
-      url_loader_modified_headers_->SetHeader(network::kAcceptHeader,
-                                              accept_value);
+      url_loader_modified_headers_.SetHeader(network::kAcceptHeader,
+                                             accept_value);
       resource_request_->headers.SetHeader(network::kAcceptHeader,
                                            accept_value);
     }
@@ -1492,8 +1489,8 @@
 
   // Caches the modified request headers provided by clients during redirect,
   // will be consumed by next |url_loader_->FollowRedirect()|.
-  base::Optional<std::vector<std::string>> url_loader_removed_headers_;
-  base::Optional<net::HttpRequestHeaders> url_loader_modified_headers_;
+  std::vector<std::string> url_loader_removed_headers_;
+  net::HttpRequestHeaders url_loader_modified_headers_;
 
   BlobHandles blob_handles_;
   std::vector<GURL> url_chain_;
@@ -1762,8 +1759,8 @@
 }
 
 void NavigationURLLoaderImpl::FollowRedirect(
-    const base::Optional<std::vector<std::string>>& removed_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_headers) {
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers) {
   base::PostTaskWithTraits(
       FROM_HERE, {BrowserThread::IO},
       base::BindOnce(&URLLoaderRequestController::FollowRedirect,
diff --git a/content/browser/loader/navigation_url_loader_impl.h b/content/browser/loader/navigation_url_loader_impl.h
index 391dac6..a8f4ab9a 100644
--- a/content/browser/loader/navigation_url_loader_impl.h
+++ b/content/browser/loader/navigation_url_loader_impl.h
@@ -45,10 +45,8 @@
   ~NavigationURLLoaderImpl() override;
 
   // NavigationURLLoader implementation:
-  void FollowRedirect(const base::Optional<std::vector<std::string>>&
-                          to_be_removed_request_headers,
-                      const base::Optional<net::HttpRequestHeaders>&
-                          modified_request_headers) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers) override;
   void ProceedWithResponse() override;
 
   void OnReceiveResponse(
diff --git a/content/browser/loader/navigation_url_loader_impl_unittest.cc b/content/browser/loader/navigation_url_loader_impl_unittest.cc
index 75b7d1a..d4cc05b 100644
--- a/content/browser/loader/navigation_url_loader_impl_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_impl_unittest.cc
@@ -223,7 +223,7 @@
                            redirect_url.GetOrigin().spec().c_str()),
         request_method, &delegate);
     delegate.WaitForRequestRedirected();
-    loader->FollowRedirect(base::nullopt, base::nullopt);
+    loader->FollowRedirect({}, {});
 
     EXPECT_EQ(expected_redirect_method, delegate.redirect_info().new_method);
 
@@ -264,7 +264,7 @@
                            url.GetOrigin().spec().c_str()),
         "GET", &delegate, NavigationDownloadPolicy::kAllow, is_main_frame);
     delegate.WaitForRequestRedirected();
-    loader->FollowRedirect(base::nullopt, base::nullopt);
+    loader->FollowRedirect({}, {});
     delegate.WaitForResponseStarted();
 
     return most_recent_resource_request_.value().priority;
@@ -281,7 +281,7 @@
         "GET", &delegate, NavigationDownloadPolicy::kAllow,
         true /*is_main_frame*/, upgrade_if_insecure);
     delegate.WaitForRequestRedirected();
-    loader->FollowRedirect(base::nullopt, base::nullopt);
+    loader->FollowRedirect({}, {});
     if (expect_request_fail) {
       delegate.WaitForRequestFailed();
     } else {
@@ -436,7 +436,7 @@
   net::HttpRequestHeaders redirect_headers;
   redirect_headers.SetHeader("Header2", "");
   redirect_headers.SetHeader("Header3", "Value3");
-  loader->FollowRedirect(base::nullopt, redirect_headers);
+  loader->FollowRedirect({}, redirect_headers);
   delegate.WaitForResponseStarted();
 
   // Redirected request should also have modified headers.
diff --git a/content/browser/loader/navigation_url_loader_unittest.cc b/content/browser/loader/navigation_url_loader_unittest.cc
index 9b8e9c0..b5a5b0e 100644
--- a/content/browser/loader/navigation_url_loader_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_unittest.cc
@@ -229,7 +229,7 @@
 
   // In the same event loop iteration, follow the redirect (allowing the
   // response to go through) and destroy the loader.
-  loader->FollowRedirect(base::nullopt, base::nullopt);
+  loader->FollowRedirect({}, {});
   loader.reset();
 
   // Verify the URLRequestTestJob no longer has anything paused and that no
diff --git a/content/browser/loader/null_resource_controller.cc b/content/browser/loader/null_resource_controller.cc
index 385864b..80f270e 100644
--- a/content/browser/loader/null_resource_controller.cc
+++ b/content/browser/loader/null_resource_controller.cc
@@ -29,9 +29,9 @@
 }
 
 void NullResourceController::ResumeForRedirect(
-    const base::Optional<std::vector<std::string>>& removed_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_headers) {
-  DCHECK(!removed_headers && !modified_headers)
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers) {
+  DCHECK(removed_headers.empty() && modified_headers.IsEmpty())
       << "Redirect with removed or modified headers is not supported yet. See "
          "https://crbug.com/845683";
   Resume();
diff --git a/content/browser/loader/null_resource_controller.h b/content/browser/loader/null_resource_controller.h
index 8df0468..b32595e 100644
--- a/content/browser/loader/null_resource_controller.h
+++ b/content/browser/loader/null_resource_controller.h
@@ -24,8 +24,8 @@
   void CancelWithError(int error_code) override;
   void Resume() override;
   void ResumeForRedirect(
-      const base::Optional<std::vector<std::string>>& removed_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_headers) override;
+      const std::vector<std::string>& removed_headers,
+      const net::HttpRequestHeaders& modified_headers) override;
 
  private:
   bool* was_resumed_;
diff --git a/content/browser/loader/prefetch_url_loader.cc b/content/browser/loader/prefetch_url_loader.cc
index 1d49d18..eec76c9 100644
--- a/content/browser/loader/prefetch_url_loader.cc
+++ b/content/browser/loader/prefetch_url_loader.cc
@@ -78,15 +78,14 @@
 PrefetchURLLoader::~PrefetchURLLoader() = default;
 
 void PrefetchURLLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
-  DCHECK(!modified_request_headers.has_value()) << "Redirect with modified "
-                                                   "headers was not supported "
-                                                   "yet. crbug.com/845683";
-  DCHECK(!new_url.has_value()) << "Redirect with modified URL was not "
-                                  "supported yet. crbug.com/845683";
+  DCHECK(removed_headers.empty() && modified_headers.IsEmpty())
+      << "Redirect with modified headers was not supported yet. "
+         "crbug.com/845683";
+  DCHECK(!new_url) << "Redirect with modified URL was not "
+                      "supported yet. crbug.com/845683";
   DCHECK(new_url_for_redirect_.is_valid());
   if (signed_exchange_prefetch_handler_) {
     // Rebind |client_binding_| and |loader_|.
@@ -95,12 +94,12 @@
     return;
   }
 
+  net::HttpRequestHeaders modified_request_headers_for_accept;
   if (signed_exchange_utils::NeedToCheckRedirectedURLForAcceptHeader()) {
     // Currently we send the SignedExchange accept header only for the limited
     // origins when SignedHTTPExchangeOriginTrial feature is enabled without
     // SignedHTTPExchange feature. So need to update the accept header by
     // checking the new URL when redirected.
-    net::HttpRequestHeaders modified_request_headers_for_accept;
     if (signed_exchange_utils::ShouldAdvertiseAcceptHeader(
             url::Origin::Create(new_url_for_redirect_))) {
       modified_request_headers_for_accept.SetHeader(
@@ -110,12 +109,10 @@
       modified_request_headers_for_accept.SetHeader(
           network::kAcceptHeader, network::kDefaultAcceptHeader);
     }
-    loader_->FollowRedirect(base::nullopt, modified_request_headers_for_accept,
-                            base::nullopt);
-    return;
   }
 
-  loader_->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+  loader_->FollowRedirect(std::vector<std::string>() /* removed_headers */,
+                          modified_request_headers_for_accept, base::nullopt);
 }
 
 void PrefetchURLLoader::ProceedWithResponse() {
diff --git a/content/browser/loader/prefetch_url_loader.h b/content/browser/loader/prefetch_url_loader.h
index db37d90..15f8751 100644
--- a/content/browser/loader/prefetch_url_loader.h
+++ b/content/browser/loader/prefetch_url_loader.h
@@ -65,11 +65,9 @@
 
  private:
   // network::mojom::URLLoader overrides:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int intra_priority_value) override;
diff --git a/content/browser/loader/resource_controller.h b/content/browser/loader/resource_controller.h
index 0f4bbb8..06f1c47 100644
--- a/content/browser/loader/resource_controller.h
+++ b/content/browser/loader/resource_controller.h
@@ -35,8 +35,8 @@
   // redirected. |removed_headers| and |modified_headers| are
   // applied to the request header after updating them for the redirect.
   virtual void ResumeForRedirect(
-      const base::Optional<std::vector<std::string>>& removed_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_headers) = 0;
+      const std::vector<std::string>& removed_headers,
+      const net::HttpRequestHeaders& modified_headers) = 0;
 };
 
 }  // namespace content
diff --git a/content/browser/loader/resource_handler.cc b/content/browser/loader/resource_handler.cc
index 86455da..0adbfc2 100644
--- a/content/browser/loader/resource_handler.cc
+++ b/content/browser/loader/resource_handler.cc
@@ -45,8 +45,8 @@
 }
 
 void ResourceHandler::ResumeForRedirect(
-    const base::Optional<std::vector<std::string>>& removed_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_headers) {
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers) {
   ReleaseController()->ResumeForRedirect(removed_headers, modified_headers);
 }
 
diff --git a/content/browser/loader/resource_handler.h b/content/browser/loader/resource_handler.h
index 23b4ee6e..4b8fdf8 100644
--- a/content/browser/loader/resource_handler.h
+++ b/content/browser/loader/resource_handler.h
@@ -159,9 +159,8 @@
   // These call the corresponding methods on the ResourceController previously
   // passed to HoldController and then destroy it.
   void Resume();
-  void ResumeForRedirect(
-      const base::Optional<std::vector<std::string>>& removed_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_headers);
+  void ResumeForRedirect(const std::vector<std::string>& removed_headers,
+                         const net::HttpRequestHeaders& modified_headers);
   void Cancel();
   void CancelWithError(int error_code);
 
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index 756a4a3..46a77d46 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -157,13 +157,13 @@
   void Resume() override {
     MarkAsUsed();
     resource_loader_->Resume(true /* called_from_resource_controller */,
-                             base::nullopt, base::nullopt);
+                             {} /* removed_headers */,
+                             {} /* modified_headers */);
   }
 
   void ResumeForRedirect(
-      const base::Optional<std::vector<std::string>>& removed_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_headers)
-      override {
+      const std::vector<std::string>& removed_headers,
+      const net::HttpRequestHeaders& modified_headers) override {
     MarkAsUsed();
     resource_loader_->Resume(true /* called_from_resource_controller */,
                              removed_headers, modified_headers);
@@ -224,7 +224,8 @@
     // anything. Go ahead and resume the request now.
     if (old_deferred_stage == DEFERRED_NONE)
       resource_loader_->Resume(false /* called_from_resource_controller */,
-                               base::nullopt, base::nullopt);
+                               {} /* removed_headers */,
+                               {} /* modified_headers */);
   }
 
  private:
@@ -530,13 +531,13 @@
   request_->CancelWithError(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
 }
 
-void ResourceLoader::Resume(
-    bool called_from_resource_controller,
-    const base::Optional<std::vector<std::string>>& removed_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_headers) {
+void ResourceLoader::Resume(bool called_from_resource_controller,
+                            const std::vector<std::string>& removed_headers,
+                            const net::HttpRequestHeaders& modified_headers) {
   DeferredStage stage = deferred_stage_;
   deferred_stage_ = DEFERRED_NONE;
-  DCHECK((!modified_headers && !removed_headers) || stage == DEFERRED_REDIRECT)
+  DCHECK((removed_headers.empty() && modified_headers.IsEmpty()) ||
+         stage == DEFERRED_REDIRECT)
       << "Modifying or removing headers can only be used with redirects";
   switch (stage) {
     case DEFERRED_NONE:
@@ -683,17 +684,14 @@
 }
 
 void ResourceLoader::FollowDeferredRedirectInternal(
-    const base::Optional<std::vector<std::string>>& removed_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_headers) {
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers) {
   DCHECK(!deferred_redirect_url_.is_empty());
   GURL redirect_url = deferred_redirect_url_;
   deferred_redirect_url_ = GURL();
   if (delegate_->HandleExternalProtocol(this, redirect_url)) {
     // Chrome doesn't make use of the request's headers to handle external
     // protocol. Modifying headers here would be useless.
-    DCHECK(!modified_headers && !removed_headers)
-        << "Modifying or removing headers after a redirect to an external "
-           "protocol is not supported yet. See https://crbug.com/845683.";
     Cancel();
   } else {
     request_->FollowDeferredRedirect(removed_headers, modified_headers);
diff --git a/content/browser/loader/resource_loader.h b/content/browser/loader/resource_loader.h
index dbed666..1c4e5a71 100644
--- a/content/browser/loader/resource_loader.h
+++ b/content/browser/loader/resource_loader.h
@@ -101,16 +101,16 @@
   // otherwise. |modified_headers| and |removed_headers| are used
   // for redirects only.
   void Resume(bool called_from_resource_controller,
-              const base::Optional<std::vector<std::string>>& removed_headers,
-              const base::Optional<net::HttpRequestHeaders>& modified_headers);
+              const std::vector<std::string>& removed_headers,
+              const net::HttpRequestHeaders& modified_headers);
   void Cancel();
   void CancelWithError(int error_code);
 
   void StartRequestInternal();
   void CancelRequestInternal(int error, bool from_renderer);
   void FollowDeferredRedirectInternal(
-      const base::Optional<std::vector<std::string>>& removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_headers);
+      const std::vector<std::string>& removed_headers,
+      const net::HttpRequestHeaders& modified_headers);
   void CompleteResponseStarted();
   // If |handle_result_async| is true, the result of the following read will be
   // handled asynchronously if it completes synchronously, unless it's EOF or an
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
index 374c25e..f71f6b9 100644
--- a/content/browser/media/session/media_session_impl.cc
+++ b/content/browser/media/session/media_session_impl.cc
@@ -115,9 +115,9 @@
 
 size_t MediaSessionImpl::PlayerIdentifier::Hash::operator()(
     const PlayerIdentifier& player_identifier) const {
-  size_t hash = BASE_HASH_NAMESPACE::hash<MediaSessionPlayerObserver*>()(
-      player_identifier.observer);
-  hash += BASE_HASH_NAMESPACE::hash<int>()(player_identifier.player_id);
+  size_t hash =
+      std::hash<MediaSessionPlayerObserver*>()(player_identifier.observer);
+  hash += std::hash<int>()(player_identifier.player_id);
   return hash;
 }
 
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 511b0d8..64f5e8a 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -1530,9 +1530,6 @@
 
 // A variation of the OpenerNavigation_DownloadPolicy test above, but uses a
 // cross-origin URL for the popup window.
-// TODO(csharrison): currently opener checks for DownloadPolicy has a bug when
-// the opener is cross-process. For now the test uses a.com and bar.a.com to get
-// cross-origin behavior but still same process.
 IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
                        CrossOriginOpenerNavigation_DownloadPolicy) {
   base::ScopedAllowBlockingForTesting allow_blocking;
@@ -1553,7 +1550,7 @@
   ShellAddedObserver shell_observer;
   EXPECT_TRUE(EvalJs(opener, JsReplace("!!window.open($1);",
                                        embedded_test_server()->GetURL(
-                                           "bar.a.com", "/title1.html")))
+                                           "bar.com", "/title1.html")))
                   .ExtractBool());
   Shell* new_shell = shell_observer.GetShell();
   EXPECT_EQ(2u, Shell::windows().size());
diff --git a/content/browser/presentation/presentation_service_impl_unittest.cc b/content/browser/presentation/presentation_service_impl_unittest.cc
index c8abad15..5110418 100644
--- a/content/browser/presentation/presentation_service_impl_unittest.cc
+++ b/content/browser/presentation/presentation_service_impl_unittest.cc
@@ -14,9 +14,9 @@
 #include <vector>
 
 #include "base/run_loop.h"
-#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/presentation_request.h"
 #include "content/public/browser/presentation_service_delegate.h"
+#include "content/public/test/mock_navigation_handle.h"
 #include "content/test/test_render_frame_host.h"
 #include "content/test/test_render_view_host.h"
 #include "content/test/test_web_contents.h"
@@ -248,9 +248,9 @@
     RenderFrameHostTester* rfh_tester = RenderFrameHostTester::For(rfh);
     if (!main_frame)
       rfh = rfh_tester->AppendChild("subframe");
-    std::unique_ptr<NavigationHandle> navigation_handle =
-        NavigationHandle::CreateNavigationHandleForTesting(GURL(), rfh, true);
-    // Destructor calls DidFinishNavigation.
+    MockNavigationHandle handle(GURL(), rfh);
+    handle.set_has_committed(true);
+    service_impl_->DidFinishNavigation(&handle);
   }
 
   void ListenForScreenAvailabilityAndWait(const GURL& url,
diff --git a/content/browser/service_worker/service_worker_installed_script_loader.cc b/content/browser/service_worker/service_worker_installed_script_loader.cc
index a9b1ad6b..f7a4096 100644
--- a/content/browser/service_worker/service_worker_installed_script_loader.cc
+++ b/content/browser/service_worker/service_worker_installed_script_loader.cc
@@ -119,9 +119,8 @@
 }
 
 void ServiceWorkerInstalledScriptLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
   // This class never returns a redirect response to its client, so should never
   // be asked to follow one.
diff --git a/content/browser/service_worker/service_worker_installed_script_loader.h b/content/browser/service_worker/service_worker_installed_script_loader.h
index b123084..863c90e 100644
--- a/content/browser/service_worker/service_worker_installed_script_loader.h
+++ b/content/browser/service_worker/service_worker_installed_script_loader.h
@@ -49,11 +49,9 @@
       ServiceWorkerInstalledScriptReader::FinishedReason reason) override;
 
   // network::mojom::URLLoader overrides:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override;
diff --git a/content/browser/service_worker/service_worker_navigation_loader.cc b/content/browser/service_worker/service_worker_navigation_loader.cc
index 35d8749..63bf477 100644
--- a/content/browser/service_worker/service_worker_navigation_loader.cc
+++ b/content/browser/service_worker/service_worker_navigation_loader.cc
@@ -487,9 +487,8 @@
 // URLLoader implementation----------------------------------------
 
 void ServiceWorkerNavigationLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
   NOTIMPLEMENTED();
 }
diff --git a/content/browser/service_worker/service_worker_navigation_loader.h b/content/browser/service_worker/service_worker_navigation_loader.h
index 0efdb83d..9f8ad0b 100644
--- a/content/browser/service_worker/service_worker_navigation_loader.h
+++ b/content/browser/service_worker/service_worker_navigation_loader.h
@@ -152,11 +152,9 @@
   void CommitCompleted(int error_code, const char* reason);
 
   // network::mojom::URLLoader:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override;
diff --git a/content/browser/service_worker/service_worker_new_script_loader.cc b/content/browser/service_worker/service_worker_new_script_loader.cc
index 2b9d819..82fd4a0c 100644
--- a/content/browser/service_worker/service_worker_new_script_loader.cc
+++ b/content/browser/service_worker/service_worker_new_script_loader.cc
@@ -137,9 +137,8 @@
 ServiceWorkerNewScriptLoader::~ServiceWorkerNewScriptLoader() = default;
 
 void ServiceWorkerNewScriptLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
   // Resource requests for service worker scripts should not follow redirects.
   // See comments in OnReceiveRedirect().
diff --git a/content/browser/service_worker/service_worker_new_script_loader.h b/content/browser/service_worker/service_worker_new_script_loader.h
index 5590008..532b50d97 100644
--- a/content/browser/service_worker/service_worker_new_script_loader.h
+++ b/content/browser/service_worker/service_worker_new_script_loader.h
@@ -75,11 +75,9 @@
   ~ServiceWorkerNewScriptLoader() override;
 
   // network::mojom::URLLoader:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override;
diff --git a/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc b/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
index 32ed0d8..d9a73e6e 100644
--- a/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
+++ b/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
@@ -81,8 +81,8 @@
   ~MockURLLoader() override = default;
 
   MOCK_METHOD3(FollowRedirect,
-               void(const base::Optional<std::vector<std::string>>&,
-                    const base::Optional<net::HttpRequestHeaders>&,
+               void(const std::vector<std::string>&,
+                    const net::HttpRequestHeaders&,
                     const base::Optional<GURL>&));
   MOCK_METHOD0(ProceedWithResponse, void());
   MOCK_METHOD2(SetPriority,
diff --git a/content/browser/web_package/signed_exchange_loader.cc b/content/browser/web_package/signed_exchange_loader.cc
index 82256ea..06e4461 100644
--- a/content/browser/web_package/signed_exchange_loader.cc
+++ b/content/browser/web_package/signed_exchange_loader.cc
@@ -234,9 +234,8 @@
     const network::URLLoaderCompletionStatus& status) {}
 
 void SignedExchangeLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
   NOTREACHED();
 }
diff --git a/content/browser/web_package/signed_exchange_loader.h b/content/browser/web_package/signed_exchange_loader.h
index 4512823..1a0e209 100644
--- a/content/browser/web_package/signed_exchange_loader.h
+++ b/content/browser/web_package/signed_exchange_loader.h
@@ -83,11 +83,9 @@
   void OnComplete(const network::URLLoaderCompletionStatus& status) override;
 
   // network::mojom::URLLoader implementation
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int intra_priority_value) override;
diff --git a/content/browser/worker_host/worker_script_fetcher.cc b/content/browser/worker_host/worker_script_fetcher.cc
index 5bbbf9b8..05b8ce7 100644
--- a/content/browser/worker_host/worker_script_fetcher.cc
+++ b/content/browser/worker_host/worker_script_fetcher.cc
@@ -165,8 +165,8 @@
     const network::ResourceResponseHead& head) {
   redirect_infos_.push_back(redirect_info);
   redirect_response_heads_.push_back(head);
-  url_loader_->FollowRedirect(base::nullopt /* removed_headers */,
-                              base::nullopt /* modified_headers */);
+  url_loader_->FollowRedirect({}, /* removed_headers */
+                              {} /* modified_headers */);
 }
 
 void WorkerScriptFetcher::OnUploadProgress(int64_t current_position,
diff --git a/content/browser/worker_host/worker_script_loader.cc b/content/browser/worker_host/worker_script_loader.cc
index dc7bd23..81fbb6a 100644
--- a/content/browser/worker_host/worker_script_loader.cc
+++ b/content/browser/worker_host/worker_script_loader.cc
@@ -133,8 +133,8 @@
 // the new URL.
 
 void WorkerScriptLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>& removed_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
   DCHECK(!new_url.has_value()) << "Redirect with modified URL was not "
                                   "supported yet. crbug.com/845683";
diff --git a/content/browser/worker_host/worker_script_loader.h b/content/browser/worker_host/worker_script_loader.h
index a390e6d..affc0c5 100644
--- a/content/browser/worker_host/worker_script_loader.h
+++ b/content/browser/worker_host/worker_script_loader.h
@@ -59,11 +59,9 @@
   ~WorkerScriptLoader() override;
 
   // network::mojom::URLLoader:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override;
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 7e59f845..fb8d097 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -483,6 +483,7 @@
     "child_control.mojom",
     "field_trial_recorder.mojom",
     "frame.mojom",
+    "frame_messages.mojom",
     "frame_sink_provider.mojom",
     "histogram_fetcher.mojom",
     "host_zoom.mojom",
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index 7e999e4..a92e669 100644
--- a/content/common/frame.mojom
+++ b/content/common/frame.mojom
@@ -4,6 +4,7 @@
 
 module content.mojom;
 
+import "content/common/frame_messages.mojom";
 import "content/common/navigation_client.mojom";
 import "content/common/navigation_params.mojom";
 import "content/public/common/resource_type.mojom";
@@ -262,9 +263,6 @@
 // the frame is detached. Used by resource requests with "keepalive" specified.
 interface KeepAliveHandle {};
 
-[Native]
-struct DidCommitProvisionalLoadParams;
-
 // Implemented by the frame server (i.e. the browser process). For messages that
 // must be associated with the IPC channel.
 interface FrameHost {
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 5738a30..da913e2 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -565,6 +565,7 @@
   IPC_STRUCT_MEMBER(blink::WebTriggeringEventInfo, triggering_event_info)
   IPC_STRUCT_MEMBER(mojo::MessagePipeHandle, blob_url_token)
   IPC_STRUCT_MEMBER(std::string, href_translate)
+  IPC_STRUCT_MEMBER(content::NavigationDownloadPolicy, download_policy)
 IPC_STRUCT_END()
 
 IPC_STRUCT_BEGIN(FrameHostMsg_DownloadUrl_Params)
diff --git a/content/common/frame_messages.mojom b/content/common/frame_messages.mojom
new file mode 100644
index 0000000..e93e582
--- /dev/null
+++ b/content/common/frame_messages.mojom
@@ -0,0 +1,9 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module content.mojom;
+
+[Native]
+struct DidCommitProvisionalLoadParams;
+
diff --git a/content/common/frame_messages.typemap b/content/common/frame_messages.typemap
index 4938511..fb260da 100644
--- a/content/common/frame_messages.typemap
+++ b/content/common/frame_messages.typemap
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-mojom = "//content/common/frame.mojom"
+mojom = "//content/common/frame_messages.mojom"
 public_headers = [ "//content/common/frame_messages_forward.h" ]
 traits_headers = [ "//content/common/frame_messages.h" ]
 type_mappings = [ "content.mojom.DidCommitProvisionalLoadParams=std::unique_ptr<::FrameHostMsg_DidCommitProvisionalLoad_Params>[move_only,nullable_is_same_type]" ]
diff --git a/content/common/mime_sniffing_url_loader.cc b/content/common/mime_sniffing_url_loader.cc
index 06ebccc..cfc245db 100644
--- a/content/common/mime_sniffing_url_loader.cc
+++ b/content/common/mime_sniffing_url_loader.cc
@@ -137,9 +137,8 @@
 }
 
 void MimeSniffingURLLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
   // MimeSniffingURLLoader starts handling the request after
   // OnReceivedResponse(). A redirect response is not expected.
diff --git a/content/common/mime_sniffing_url_loader.h b/content/common/mime_sniffing_url_loader.h
index 9c10ba56..960c03a 100644
--- a/content/common/mime_sniffing_url_loader.h
+++ b/content/common/mime_sniffing_url_loader.h
@@ -94,11 +94,9 @@
 
   // network::mojom::URLLoader implementation (called from the destination of
   // the response):
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override;
diff --git a/content/common/throttling_url_loader.cc b/content/common/throttling_url_loader.cc
index 3adb75e..502eb932 100644
--- a/content/common/throttling_url_loader.cc
+++ b/content/common/throttling_url_loader.cc
@@ -15,35 +15,13 @@
 
 namespace {
 
-// Merges |removed_headers_B| into |removed_headers_A|. Handles the cases where
-// any of them are base::nullopt.
-void MergeRemovedHeaders(
-    base::Optional<std::vector<std::string>>* removed_headers_A,
-    const base::Optional<std::vector<std::string>>& removed_headers_B) {
-  if (!removed_headers_B || removed_headers_B->empty())
-    return;
-  if (!*removed_headers_A) {
-    *removed_headers_A = removed_headers_B;
-    return;
+// Merges |removed_headers_B| into |removed_headers_A|.
+void MergeRemovedHeaders(std::vector<std::string>* removed_headers_A,
+                         const std::vector<std::string>& removed_headers_B) {
+  for (auto& header : removed_headers_B) {
+    if (!base::ContainsValue(*removed_headers_A, header))
+      removed_headers_A->emplace_back(std::move(header));
   }
-  for (auto& header : *removed_headers_B) {
-    if (!base::ContainsValue(**removed_headers_A, header))
-      (**removed_headers_A).emplace_back(std::move(header));
-  }
-}
-
-// Merges |modified_headers_B| into |modified_headers_A|. Handles the cases
-// where any of them are base::nullopt.
-void MergeModifiedHeaders(
-    base::Optional<net::HttpRequestHeaders>* modified_headers_A,
-    const base::Optional<net::HttpRequestHeaders>& modified_headers_B) {
-  if (!modified_headers_B || modified_headers_B->IsEmpty())
-    return;
-  if (!*modified_headers_A) {
-    *modified_headers_A = modified_headers_B;
-    return;
-  }
-  (**modified_headers_A).MergeFrom(*modified_headers_B);
 }
 
 }  // namespace
@@ -233,10 +211,10 @@
 }
 
 void ThrottlingURLLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>& removed_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_headers) {
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers) {
   MergeRemovedHeaders(&removed_headers_, removed_headers);
-  MergeModifiedHeaders(&modified_headers_, modified_headers);
+  modified_headers_.MergeFrom(modified_headers);
 
   if (!throttle_will_start_redirect_url_.is_empty()) {
     throttle_will_start_redirect_url_ = GURL();
@@ -253,8 +231,8 @@
     throttle_will_redirect_redirect_url_ = GURL();
   }
 
-  removed_headers_.reset();
-  modified_headers_.reset();
+  removed_headers_.clear();
+  modified_headers_.Clear();
 }
 
 void ThrottlingURLLoader::FollowRedirectForcingRestart() {
@@ -262,16 +240,12 @@
   client_binding_.Close();
   CHECK(throttle_will_redirect_redirect_url_.is_empty());
 
-  if (removed_headers_) {
-    for (const std::string& key : *removed_headers_)
-      start_info_->url_request.headers.RemoveHeader(key);
-    removed_headers_.reset();
-  }
+  for (const std::string& header : removed_headers_)
+    start_info_->url_request.headers.RemoveHeader(header);
+  start_info_->url_request.headers.MergeFrom(modified_headers_);
 
-  if (modified_headers_) {
-    start_info_->url_request.headers.MergeFrom(*modified_headers_);
-    modified_headers_.reset();
-  }
+  removed_headers_.clear();
+  modified_headers_.Clear();
 
   StartNow();
 }
@@ -567,7 +541,7 @@
         return;
 
       MergeRemovedHeaders(&removed_headers_, removed_headers);
-      MergeModifiedHeaders(&modified_headers_, modified_headers);
+      modified_headers_.MergeFrom(modified_headers);
     }
 
     if (deferred) {
diff --git a/content/common/throttling_url_loader.h b/content/common/throttling_url_loader.h
index 91640ca..6255f8ff 100644
--- a/content/common/throttling_url_loader.h
+++ b/content/common/throttling_url_loader.h
@@ -50,9 +50,8 @@
 
   ~ThrottlingURLLoader() override;
 
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>& removed_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_headers);
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers);
   // Follows a redirect, calling CreateLoaderAndStart() on the factory. This
   // is useful if the factory uses different loaders for different URLs.
   void FollowRedirectForcingRestart();
@@ -255,8 +254,8 @@
 
   bool response_intercepted_ = false;
 
-  base::Optional<std::vector<std::string>> removed_headers_;
-  base::Optional<net::HttpRequestHeaders> modified_headers_;
+  std::vector<std::string> removed_headers_;
+  net::HttpRequestHeaders modified_headers_;
 
   int pending_restart_flags_ = 0;
   bool has_pending_restart_ = false;
diff --git a/content/common/throttling_url_loader_unittest.cc b/content/common/throttling_url_loader_unittest.cc
index 05dce1c..4b76a9da 100644
--- a/content/common/throttling_url_loader_unittest.cc
+++ b/content/common/throttling_url_loader_unittest.cc
@@ -47,13 +47,11 @@
     return create_loader_and_start_called_;
   }
 
-  const base::Optional<std::vector<std::string>>& headers_removed_on_redirect()
-      const {
+  const std::vector<std::string>& headers_removed_on_redirect() const {
     return headers_removed_on_redirect_;
   }
 
-  const base::Optional<net::HttpRequestHeaders>& headers_modified_on_redirect()
-      const {
+  const net::HttpRequestHeaders& headers_modified_on_redirect() const {
     return headers_modified_on_redirect_;
   }
 
@@ -117,13 +115,11 @@
   }
 
   // network::mojom::URLLoader implementation.
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override {
-    headers_removed_on_redirect_ = to_be_removed_request_headers;
-    headers_modified_on_redirect_ = modified_request_headers;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override {
+    headers_removed_on_redirect_ = removed_headers;
+    headers_modified_on_redirect_ = modified_headers;
   }
 
   void ProceedWithResponse() override {}
@@ -140,8 +136,8 @@
   }
 
   size_t create_loader_and_start_called_ = 0;
-  base::Optional<std::vector<std::string>> headers_removed_on_redirect_;
-  base::Optional<net::HttpRequestHeaders> headers_modified_on_redirect_;
+  std::vector<std::string> headers_removed_on_redirect_;
+  net::HttpRequestHeaders headers_modified_on_redirect_;
   size_t pause_reading_body_from_net_called_ = 0;
   size_t resume_reading_body_from_net_called_ = 0;
 
@@ -293,17 +289,15 @@
       will_start_request_callback_.Run(delegate_, defer);
   }
 
-  void WillRedirectRequest(
-      net::RedirectInfo* redirect_info,
-      const network::ResourceResponseHead& response_head,
-      bool* defer,
-      std::vector<std::string>* to_be_removed_request_headers,
-      net::HttpRequestHeaders* modified_request_headers) override {
+  void WillRedirectRequest(net::RedirectInfo* redirect_info,
+                           const network::ResourceResponseHead& response_head,
+                           bool* defer,
+                           std::vector<std::string>* removed_headers,
+                           net::HttpRequestHeaders* modified_headers) override {
     will_redirect_request_called_++;
     if (will_redirect_request_callback_) {
-      will_redirect_request_callback_.Run(delegate_, defer,
-                                          to_be_removed_request_headers,
-                                          modified_request_headers);
+      will_redirect_request_callback_.Run(delegate_, defer, removed_headers,
+                                          modified_headers);
     }
   }
 
@@ -581,22 +575,23 @@
     net::HttpRequestHeaders modified_headers;
     modified_headers.SetHeader("X-Test-Header-3", "Client Value");
     modified_headers.SetHeader("X-Test-Header-4", "Bar");
-    loader_->FollowRedirect(base::nullopt, modified_headers);
+    loader_->FollowRedirect({} /* removed_headers */,
+                            std::move(modified_headers));
   }));
 
   CreateLoaderAndStart();
   factory_.NotifyClientOnReceiveRedirect();
   base::RunLoop().RunUntilIdle();
 
-  ASSERT_TRUE(factory_.headers_removed_on_redirect().has_value());
-  EXPECT_THAT(*factory_.headers_removed_on_redirect(),
+  ASSERT_FALSE(factory_.headers_removed_on_redirect().empty());
+  EXPECT_THAT(factory_.headers_removed_on_redirect(),
               testing::ElementsAre("X-Test-Header-1"));
-  ASSERT_TRUE(factory_.headers_modified_on_redirect().has_value());
+  ASSERT_FALSE(factory_.headers_modified_on_redirect().IsEmpty());
   EXPECT_EQ(
       "X-Test-Header-2: Foo\r\n"
       "X-Test-Header-3: Client Value\r\n"
       "X-Test-Header-4: Bar\r\n\r\n",
-      factory_.headers_modified_on_redirect()->ToString());
+      factory_.headers_modified_on_redirect().ToString());
 }
 
 TEST_F(ThrottlingURLLoaderTest, MultipleThrottlesModifyHeadersBeforeRedirect) {
@@ -622,22 +617,22 @@
         modified_headers->SetHeader("X-Test-Header-4", "Throttle2");
       }));
 
-  client_.set_on_received_redirect_callback(base::BindLambdaForTesting(
-      [&]() { loader_->FollowRedirect(base::nullopt, base::nullopt); }));
+  client_.set_on_received_redirect_callback(
+      base::BindLambdaForTesting([&]() { loader_->FollowRedirect({}, {}); }));
 
   CreateLoaderAndStart();
   factory_.NotifyClientOnReceiveRedirect();
   base::RunLoop().RunUntilIdle();
 
-  ASSERT_TRUE(factory_.headers_removed_on_redirect().has_value());
-  EXPECT_THAT(*factory_.headers_removed_on_redirect(),
+  ASSERT_FALSE(factory_.headers_removed_on_redirect().empty());
+  EXPECT_THAT(factory_.headers_removed_on_redirect(),
               testing::ElementsAre("X-Test-Header-0", "X-Test-Header-1",
                                    "X-Test-Header-2"));
-  ASSERT_TRUE(factory_.headers_modified_on_redirect().has_value());
+  ASSERT_FALSE(factory_.headers_modified_on_redirect().IsEmpty());
   EXPECT_EQ(
       "X-Test-Header-3: Foo\r\n"
       "X-Test-Header-4: Throttle2\r\n\r\n",
-      factory_.headers_modified_on_redirect()->ToString());
+      factory_.headers_modified_on_redirect().ToString());
 }
 
 TEST_F(ThrottlingURLLoaderTest, CancelBeforeResponse) {
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index a018e24..cde35f74 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -552,11 +552,10 @@
 
   // Allow the embedder to return additional headers that should be sent when
   // fetching |url| as well as add extra load flags.
-  virtual void NavigationRequestStarted(
-      int frame_tree_node_id,
-      const GURL& url,
-      std::unique_ptr<net::HttpRequestHeaders>* extra_headers,
-      int* extra_load_flags) {}
+  virtual void NavigationRequestStarted(int frame_tree_node_id,
+                                        const GURL& url,
+                                        net::HttpRequestHeaders* extra_headers,
+                                        int* extra_load_flags) {}
 
   // Allow the embedder to modify headers for a redirect. If non-nullopt,
   // |*modified_headers| is applied to the request headers after updating them
@@ -564,7 +563,7 @@
   virtual void NavigationRequestRedirected(
       int frame_tree_node_id,
       const GURL& url,
-      base::Optional<net::HttpRequestHeaders>* modified_headers) {}
+      net::HttpRequestHeaders* modified_headers) {}
 
   // Allow the embedder to control if the given cookie can be read.
   // This is called on the IO thread.
diff --git a/content/public/browser/navigation_handle.cc b/content/public/browser/navigation_handle.cc
index 9f55b85..86cd2a6 100644
--- a/content/public/browser/navigation_handle.cc
+++ b/content/public/browser/navigation_handle.cc
@@ -20,46 +20,4 @@
       static_cast<NavigationHandleImpl*>(this)->GetDelegate());
 }
 
-// static
-std::unique_ptr<NavigationHandle>
-NavigationHandle::CreateNavigationHandleForTesting(
-    const GURL& url,
-    RenderFrameHost* render_frame_host,
-    bool committed,
-    net::Error error,
-    bool is_same_document,
-    bool is_post,
-    ui::PageTransition transition,
-    bool is_form_submission) {
-  RenderFrameHostImpl* rfhi =
-      static_cast<RenderFrameHostImpl*>(render_frame_host);
-  scoped_refptr<network::ResourceRequestBody> resource_request_body;
-  std::string method = "GET";
-  if (is_post) {
-    method = "POST";
-
-    std::string body = "test=body";
-    resource_request_body = new network::ResourceRequestBody();
-    resource_request_body->AppendBytes(body.data(), body.size());
-  }
-  std::unique_ptr<NavigationHandleImpl> handle_impl =
-      NavigationHandleImpl::Create(
-          url, base::nullopt, std::vector<GURL>(), rfhi->frame_tree_node(),
-          true,  // is_renderer_initiated
-          is_same_document, base::TimeTicks::Now(), 0,
-          false,                  // started_from_context_menu
-          CSPDisposition::CHECK,  // should_check_main_world_csp
-          is_form_submission,     // is_form_submission
-          nullptr,                // navigation_ui_data
-          method, net::HttpRequestHeaders(), resource_request_body, Referrer(),
-          false,  // has_user_gesture
-          transition);
-  handle_impl->set_render_frame_host(rfhi);
-  if (error != net::OK)
-    handle_impl->set_net_error_code(error);
-  if (committed)
-    handle_impl->CallDidCommitNavigationForTesting(url);
-  return std::unique_ptr<NavigationHandle>(std::move(handle_impl));
-}
-
 }  // namespace content
diff --git a/content/public/browser/navigation_handle.h b/content/public/browser/navigation_handle.h
index 66c96ef8..c33548f 100644
--- a/content/public/browser/navigation_handle.h
+++ b/content/public/browser/navigation_handle.h
@@ -102,7 +102,7 @@
   virtual RenderFrameHost* GetParentFrame() = 0;
 
   // The WebContents the navigation is taking place in.
-  WebContents* GetWebContents();
+  virtual WebContents* GetWebContents();
 
   // The time the navigation started, recorded either in the renderer or in the
   // browser process. Corresponds to Navigation Timing API.
@@ -293,16 +293,6 @@
   //
   // The following methods should be used exclusively for writing unit tests.
 
-  static std::unique_ptr<NavigationHandle> CreateNavigationHandleForTesting(
-      const GURL& url,
-      RenderFrameHost* render_frame_host,
-      bool committed = false,
-      net::Error error = net::OK,
-      bool is_same_document = false,
-      bool is_post = false,
-      ui::PageTransition transition = ui::PAGE_TRANSITION_LINK,
-      bool is_form_submission = false);
-
   // Registers a NavigationThrottle for tests. The throttle can
   // modify the request, pause the request or cancel the request. This will
   // take ownership of the NavigationThrottle.
@@ -313,36 +303,6 @@
   virtual void RegisterThrottleForTesting(
       std::unique_ptr<NavigationThrottle> navigation_throttle) = 0;
 
-  // Simulates the network request starting.
-  virtual NavigationThrottle::ThrottleCheckResult
-  CallWillStartRequestForTesting() = 0;
-
-  // Simulates the network request being redirected.
-  virtual NavigationThrottle::ThrottleCheckResult
-  CallWillRedirectRequestForTesting(const GURL& new_url,
-                                    bool new_method_is_post,
-                                    const GURL& new_referrer_url,
-                                    bool new_is_external_protocol) = 0;
-
-  // Simulates the network request failing.
-  virtual NavigationThrottle::ThrottleCheckResult CallWillFailRequestForTesting(
-      RenderFrameHost* render_frame_host,
-      base::Optional<net::SSLInfo> ssl_info) = 0;
-
-  // Simulates the reception of the network response.
-  virtual NavigationThrottle::ThrottleCheckResult
-  CallWillProcessResponseForTesting(RenderFrameHost* render_frame_host,
-                                    const std::string& raw_response_headers,
-                                    bool was_cached,
-                                    const net::ProxyServer& proxy_server) = 0;
-
-  // Simulates the navigation being committed.
-  virtual void CallDidCommitNavigationForTesting(const GURL& url) = 0;
-
-  // Simulates the navigation resuming. Most callers should just let the
-  // deferring NavigationThrottle do the resuming.
-  virtual void CallResumeForTesting() = 0;
-
   // Returns whether this navigation is currently deferred.
   virtual bool IsDeferredForTesting() = 0;
 
diff --git a/content/public/browser/navigation_throttle.cc b/content/public/browser/navigation_throttle.cc
index 1bef677..14270f9 100644
--- a/content/public/browser/navigation_throttle.cc
+++ b/content/public/browser/navigation_throttle.cc
@@ -81,6 +81,10 @@
 }
 
 void NavigationThrottle::Resume() {
+  if (!resume_callback_.is_null()) {
+    resume_callback_.Run();
+    return;
+  }
   static_cast<NavigationHandleImpl*>(navigation_handle_)->Resume(this);
 }
 
diff --git a/content/public/browser/navigation_throttle.h b/content/public/browser/navigation_throttle.h
index e1157c4..a25f91a5 100644
--- a/content/public/browser/navigation_throttle.h
+++ b/content/public/browser/navigation_throttle.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_PUBLIC_BROWSER_NAVIGATION_THROTTLE_H_
 #define CONTENT_PUBLIC_BROWSER_NAVIGATION_THROTTLE_H_
 
+#include "base/callback.h"
 #include "base/optional.h"
 #include "content/common/content_export.h"
 #include "net/base/net_errors.h"
@@ -173,6 +174,12 @@
   // navigation.
   NavigationHandle* navigation_handle() const { return navigation_handle_; }
 
+  // Overrides the default Resume method and replaces it by |callback|. This
+  // should only be used in tests.
+  void set_resume_callback_for_testing(const base::RepeatingClosure& callback) {
+    resume_callback_ = callback;
+  }
+
  protected:
   // Resumes a navigation that was previously deferred by this
   // NavigationThrottle.
@@ -191,6 +198,9 @@
 
  private:
   NavigationHandle* navigation_handle_;
+
+  // Used in tests.
+  base::RepeatingClosure resume_callback_;
 };
 
 #if defined(UNIT_TEST)
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 6f604ca7..17104263 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -41,6 +41,7 @@
 #include "content/browser/frame_host/cross_process_frame_connector.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/interstitial_page_impl.h"
+#include "content/browser/frame_host/navigation_handle_impl.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/frame_host/render_widget_host_view_guest.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
@@ -2677,7 +2678,7 @@
   if (!ShouldMonitorNavigation(handle))
     return;
 
-  handle_ = handle;
+  handle_ = static_cast<NavigationHandleImpl*>(handle);
   std::unique_ptr<NavigationThrottle> throttle(
       new TestNavigationManagerThrottle(
           handle_, base::Bind(&TestNavigationManager::OnWillStartRequest,
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 3effe69..e92c99ce 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -83,6 +83,7 @@
 class FrameTreeNode;
 class InterstitialPage;
 class NavigationHandle;
+class NavigationHandleImpl;
 class RenderWidgetHost;
 class RenderWidgetHostView;
 class WebContents;
@@ -1395,7 +1396,7 @@
   void OnNavigationStateChanged();
 
   const GURL url_;
-  NavigationHandle* handle_;
+  NavigationHandleImpl* handle_;
   bool navigation_paused_;
   NavigationState current_state_;
   NavigationState desired_state_;
diff --git a/content/public/test/mock_navigation_handle.cc b/content/public/test/mock_navigation_handle.cc
new file mode 100644
index 0000000..fb249a8
--- /dev/null
+++ b/content/public/test/mock_navigation_handle.cc
@@ -0,0 +1,35 @@
+// Copyright 2018 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/mock_navigation_handle.h"
+
+#include "content/public/browser/web_contents.h"
+
+namespace content {
+
+namespace {
+
+uint64_t g_mock_handle_id = 0;
+
+}  // namespace
+
+MockNavigationHandle::MockNavigationHandle() : MockNavigationHandle(nullptr) {}
+
+MockNavigationHandle::MockNavigationHandle(WebContents* web_contents)
+    : navigation_id_(++g_mock_handle_id), web_contents_(web_contents) {
+  proxy_server_ = net::ProxyServer::Direct();
+}
+
+MockNavigationHandle::MockNavigationHandle(const GURL& url,
+                                           RenderFrameHost* render_frame_host)
+    : navigation_id_(++g_mock_handle_id),
+      url_(url),
+      web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
+      render_frame_host_(render_frame_host) {
+  proxy_server_ = net::ProxyServer::Direct();
+}
+
+MockNavigationHandle::~MockNavigationHandle() = default;
+
+}  // namespace content
diff --git a/content/public/test/mock_navigation_handle.h b/content/public/test/mock_navigation_handle.h
new file mode 100644
index 0000000..e0482e8
--- /dev/null
+++ b/content/public/test/mock_navigation_handle.h
@@ -0,0 +1,148 @@
+// Copyright 2018 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_MOCK_NAVIGATION_HANDLE_H_
+#define CONTENT_PUBLIC_TEST_MOCK_NAVIGATION_HANDLE_H_
+
+#include "content/public/browser/global_request_id.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class MockNavigationHandle : public NavigationHandle {
+ public:
+  MockNavigationHandle();
+  explicit MockNavigationHandle(WebContents* web_contents);
+  MockNavigationHandle(const GURL& url, RenderFrameHost* render_frame_host);
+  ~MockNavigationHandle() override;
+
+  // NavigationHandle implementation:
+  int64_t GetNavigationId() const override { return navigation_id_; }
+  const GURL& GetURL() override { return url_; }
+  SiteInstance* GetStartingSiteInstance() override {
+    return starting_site_instance_;
+  }
+  bool IsInMainFrame() override {
+    return render_frame_host_ ? !render_frame_host_->GetParent() : true;
+  }
+  MOCK_METHOD0(IsParentMainFrame, bool());
+  bool IsRendererInitiated() override { return true; }
+  MOCK_METHOD0(GetFrameTreeNodeId, int());
+  RenderFrameHost* GetParentFrame() override {
+    return render_frame_host_ ? render_frame_host_->GetParent() : nullptr;
+  }
+  WebContents* GetWebContents() override { return web_contents_; }
+  MOCK_METHOD0(NavigationStart, base::TimeTicks());
+  MOCK_METHOD0(NavigationInputStart, base::TimeTicks());
+  MOCK_CONST_METHOD0(WasStartedFromContextMenu, bool());
+  MOCK_METHOD0(GetSearchableFormURL, const GURL&());
+  MOCK_METHOD0(GetSearchableFormEncoding, const std::string&());
+  MOCK_METHOD0(GetReloadType, ReloadType());
+  RestoreType GetRestoreType() override { return RestoreType::NONE; }
+  const GURL& GetBaseURLForDataURL() override { return base_url_for_data_url_; }
+  MOCK_METHOD0(IsPost, bool());
+  MOCK_METHOD0(GetResourceRequestBody,
+               const scoped_refptr<network::ResourceRequestBody>&());
+  const Referrer& GetReferrer() override { return referrer_; }
+  MOCK_METHOD0(HasUserGesture, bool());
+  ui::PageTransition GetPageTransition() override { return page_transition_; }
+  MOCK_METHOD0(GetNavigationUIData, const NavigationUIData*());
+  MOCK_METHOD0(IsExternalProtocol, bool());
+  net::Error GetNetErrorCode() override { return net_error_code_; }
+  RenderFrameHost* GetRenderFrameHost() override { return render_frame_host_; }
+  bool IsSameDocument() override { return is_same_document_; }
+  MOCK_METHOD0(WasServerRedirect, bool());
+  const std::vector<GURL>& GetRedirectChain() override {
+    return redirect_chain_;
+  }
+  bool HasCommitted() override { return has_committed_; }
+  bool IsErrorPage() override { return is_error_page_; }
+  MOCK_METHOD0(HasSubframeNavigationEntryCommitted, bool());
+  MOCK_METHOD0(DidReplaceEntry, bool());
+  MOCK_METHOD0(ShouldUpdateHistory, bool());
+  MOCK_METHOD0(GetPreviousURL, const GURL&());
+  MOCK_METHOD0(GetSocketAddress, net::HostPortPair());
+  MOCK_METHOD0(GetRequestHeaders, const net::HttpRequestHeaders&());
+  const net::HttpResponseHeaders* GetResponseHeaders() override {
+    return response_headers_;
+  }
+  MOCK_METHOD0(GetConnectionInfo, net::HttpResponseInfo::ConnectionInfo());
+  const net::SSLInfo& GetSSLInfo() override { return ssl_info_; }
+  MOCK_METHOD0(GetGlobalRequestID, const GlobalRequestID&());
+  MOCK_METHOD0(IsDownload, bool());
+  bool IsFormSubmission() override { return is_form_submission_; }
+  MOCK_METHOD0(IsSignedExchangeInnerResponse, bool());
+  bool WasResponseCached() override { return was_response_cached_; }
+  const net::ProxyServer& GetProxyServer() override { return proxy_server_; }
+  MOCK_METHOD0(GetHrefTranslate, const std::string&());
+  MOCK_METHOD0(GetInitiatorOrigin, const base::Optional<url::Origin>&());
+  MOCK_METHOD1(RegisterThrottleForTesting,
+               void(std::unique_ptr<NavigationThrottle>));
+  MOCK_METHOD0(IsDeferredForTesting, bool());
+  NavigationData* GetNavigationData() override { return nullptr; }
+  MOCK_METHOD1(RegisterSubresourceOverride,
+               void(mojom::TransferrableURLLoaderPtr));
+
+  void set_url(const GURL& url) { url_ = url; }
+  void set_starting_site_instance(SiteInstance* site_instance) {
+    starting_site_instance_ = site_instance;
+  }
+  void set_page_transition(ui::PageTransition page_transition) {
+    page_transition_ = page_transition;
+  }
+  void set_net_error_code(net::Error error_code) {
+    net_error_code_ = error_code;
+  }
+  void set_render_frame_host(RenderFrameHost* render_frame_host) {
+    render_frame_host_ = render_frame_host;
+  }
+  void set_is_same_document(bool is_same_document) {
+    is_same_document_ = is_same_document;
+  }
+  void set_redirect_chain(const std::vector<GURL>& redirect_chain) {
+    redirect_chain_ = redirect_chain;
+  }
+  void set_has_committed(bool has_committed) { has_committed_ = has_committed; }
+  void set_is_error_page(bool is_error_page) { is_error_page_ = is_error_page; }
+  void set_response_headers(net::HttpResponseHeaders* reponse_headers) {
+    response_headers_ = reponse_headers;
+  }
+  void set_ssl_info(const net::SSLInfo& ssl_info) { ssl_info_ = ssl_info; }
+  void set_is_form_submission(bool is_form_submission) {
+    is_form_submission_ = is_form_submission;
+  }
+  void set_was_response_cached(bool was_response_cached) {
+    was_response_cached_ = was_response_cached;
+  }
+  void set_proxy_server(const net::ProxyServer& proxy_server) {
+    proxy_server_ = proxy_server;
+  }
+
+ private:
+  int64_t navigation_id_;
+  GURL url_;
+  SiteInstance* starting_site_instance_ = nullptr;
+  WebContents* web_contents_ = nullptr;
+  GURL base_url_for_data_url_;
+  Referrer referrer_;
+  ui::PageTransition page_transition_ = ui::PAGE_TRANSITION_LINK;
+  net::Error net_error_code_ = net::OK;
+  RenderFrameHost* render_frame_host_ = nullptr;
+  bool is_same_document_ = false;
+  std::vector<GURL> redirect_chain_;
+  bool has_committed_ = false;
+  bool is_error_page_ = false;
+  net::HttpResponseHeaders* response_headers_ = nullptr;
+  net::SSLInfo ssl_info_;
+  bool is_form_submission_ = false;
+  bool was_response_cached_ = false;
+  net::ProxyServer proxy_server_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_TEST_MOCK_NAVIGATION_HANDLE_H_
diff --git a/content/public/test/navigation_simulator.cc b/content/public/test/navigation_simulator.cc
index 4029c13..0c4a355 100644
--- a/content/public/test/navigation_simulator.cc
+++ b/content/public/test/navigation_simulator.cc
@@ -969,7 +969,8 @@
 
   if (IsPerNavigationMojoInterfaceEnabled()) {
     mojom::NavigationClientAssociatedPtr navigation_client_ptr;
-    mojo::MakeRequestAssociatedWithDedicatedPipe(&navigation_client_ptr);
+    navigation_client_request_ =
+        mojo::MakeRequestAssociatedWithDedicatedPipe(&navigation_client_ptr);
     render_frame_host_->frame_host_binding_for_testing()
         .impl()
         ->BeginNavigation(common_params, std::move(begin_params), nullptr,
diff --git a/content/public/test/navigation_simulator.h b/content/public/test/navigation_simulator.h
index d5cdf2a3..2df0ade 100644
--- a/content/public/test/navigation_simulator.h
+++ b/content/public/test/navigation_simulator.h
@@ -32,6 +32,10 @@
 class TestRenderFrameHost;
 struct Referrer;
 
+namespace mojom {
+class NavigationClient;
+}
+
 // An interface for simulating a navigation in unit tests. Supports both
 // renderer and browser-initiated navigations.
 // Note: this should not be used in browser tests.
@@ -430,6 +434,14 @@
   // result. Calling this will quit the nested run loop.
   base::OnceClosure wait_closure_;
 
+  // This member simply ensures that we do not disconnect
+  // the NavigationClient interface, as it would be interpreted as a
+  // cancellation coming from the renderer process side. This member interface
+  // will never be bound.
+  // Only used when PerNavigationMojoInterface is enabled.
+  mojo::AssociatedInterfaceRequest<mojom::NavigationClient>
+      navigation_client_request_;
+
   base::WeakPtrFactory<NavigationSimulator> weak_factory_;
 };
 
diff --git a/content/renderer/fetchers/resource_fetcher_impl.cc b/content/renderer/fetchers/resource_fetcher_impl.cc
index a9bd7e6..ae4f748 100644
--- a/content/renderer/fetchers/resource_fetcher_impl.cc
+++ b/content/renderer/fetchers/resource_fetcher_impl.cc
@@ -186,7 +186,7 @@
       const net::RedirectInfo& redirect_info,
       const network::ResourceResponseHead& response_head) override {
     DCHECK_EQ(Status::kStarted, status_);
-    loader_->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+    loader_->FollowRedirect({}, {}, base::nullopt);
     response_.SetCurrentRequestUrl(redirect_info.new_url);
   }
   void OnUploadProgress(int64_t current_position,
diff --git a/content/renderer/loader/child_url_loader_factory_bundle.cc b/content/renderer/loader/child_url_loader_factory_bundle.cc
index 91d4fb32..7ec6cc3 100644
--- a/content/renderer/loader/child_url_loader_factory_bundle.cc
+++ b/content/renderer/loader/child_url_loader_factory_bundle.cc
@@ -30,18 +30,18 @@
         client_sink_(std::move(client_sink)) {}
 
   // network::mojom::URLLoader implementation:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override {
-    DCHECK(!modified_request_headers.has_value())
-        << "Redirect with modified headers was not supported yet. "
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_request_headers,
+                      const base::Optional<GURL>& new_url) override {
+    DCHECK(removed_headers.empty() && modified_request_headers.IsEmpty())
+        << "Redirect with removed or modified headers was not supported yet. "
            "crbug.com/845683";
     DCHECK(!new_url.has_value())
         << "Redirect with modified URL was not supported yet. "
            "crbug.com/845683";
-    loader_sink_->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+    loader_sink_->FollowRedirect({} /* removed_headers */,
+                                 {} /* modified_headers */,
+                                 base::nullopt /* new_url */);
   }
 
   void ProceedWithResponse() override { loader_sink_->ProceedWithResponse(); }
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc
index 09f05b19..1191d1d 100644
--- a/content/renderer/loader/resource_dispatcher.cc
+++ b/content/renderer/loader/resource_dispatcher.cc
@@ -462,9 +462,8 @@
     if (request_info->redirect_requires_loader_restart) {
       request_info->url_loader->FollowRedirectForcingRestart();
     } else {
-      request_info->url_loader->FollowRedirect(
-          base::nullopt /* removed_headers */,
-          base::nullopt /* modified_headers */);
+      request_info->url_loader->FollowRedirect({} /* removed_headers */,
+                                               {} /* modified_headers */);
     }
   }
 }
diff --git a/content/renderer/manifest/manifest_parser.cc b/content/renderer/manifest/manifest_parser.cc
index 7c2cd912..bb10b54b 100644
--- a/content/renderer/manifest/manifest_parser.cc
+++ b/content/renderer/manifest/manifest_parser.cc
@@ -299,7 +299,7 @@
   return sizes;
 }
 
-std::vector<blink::Manifest::ImageResource::Purpose>
+base::Optional<std::vector<blink::Manifest::ImageResource::Purpose>>
 ManifestParser::ParseIconPurpose(const base::DictionaryValue& icon) {
   base::NullableString16 purpose_str = ParseString(icon, "purpose", NoTrim);
   std::vector<blink::Manifest::ImageResource::Purpose> purposes;
@@ -312,6 +312,15 @@
   std::vector<base::string16> keywords = base::SplitString(
       purpose_str.string(), base::ASCIIToUTF16(" "),
       base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+
+  // "any" is the default if there are no other keywords.
+  if (keywords.empty()) {
+    purposes.push_back(blink::Manifest::ImageResource::Purpose::ANY);
+    return purposes;
+  }
+
+  bool unrecognised_purpose = false;
+
   for (const base::string16& keyword : keywords) {
     if (base::LowerCaseEqualsASCII(keyword, "any")) {
       purposes.push_back(blink::Manifest::ImageResource::Purpose::ANY);
@@ -320,14 +329,20 @@
     } else if (base::LowerCaseEqualsASCII(keyword, "maskable")) {
       purposes.push_back(blink::Manifest::ImageResource::Purpose::MASKABLE);
     } else {
-      AddErrorInfo(
-          "found icon with invalid purpose. "
-          "Using default value 'any'.");
+      unrecognised_purpose = true;
     }
   }
 
+  // This implies there was at least one purpose given, but none recognised.
+  // Instead of defaulting to "any" (which would not be future proof),
+  // invalidate the whole icon.
   if (purposes.empty()) {
-    purposes.push_back(blink::Manifest::ImageResource::Purpose::ANY);
+    AddErrorInfo("found icon with no valid purpose; ignoring it.");
+    return base::nullopt;
+  } else if (unrecognised_purpose) {
+    AddErrorInfo(
+        "found icon with one or more invalid purposes; those purposes are "
+        "ignored.");
   }
 
   return purposes;
@@ -355,9 +370,14 @@
     // An icon MUST have a valid src. If it does not, it MUST be ignored.
     if (!icon.src.is_valid())
       continue;
+
     icon.type = ParseIconType(*icon_dictionary);
     icon.sizes = ParseIconSizes(*icon_dictionary);
-    icon.purpose = ParseIconPurpose(*icon_dictionary);
+    auto purpose = ParseIconPurpose(*icon_dictionary);
+    if (!purpose)
+      continue;
+
+    icon.purpose = std::move(*purpose);
 
     icons.push_back(icon);
   }
@@ -387,15 +407,28 @@
     return accept_types;
   }
 
-  const base::ListValue* accept_list = nullptr;
-  if (!dictionary.GetList("accept", &accept_list)) {
-    AddErrorInfo("property 'accept' ignored, type array expected.");
-    accept_types.push_back(base::ASCIIToUTF16("invalid mimetype"));
+  base::string16 accept_str;
+  if (dictionary.GetString("accept", &accept_str)) {
+    accept_types.push_back(accept_str);
     return accept_types;
   }
 
-  for (const base::Value& accept_value : accept_list->GetList())
+  const base::ListValue* accept_list = nullptr;
+  if (!dictionary.GetList("accept", &accept_list)) {
+    // 'accept' property is the wrong type. Returning an empty vector here
+    // causes the 'files' entry to be discarded.
+    AddErrorInfo("property 'accept' ignored, type array or string expected.");
+    return accept_types;
+  }
+
+  for (const base::Value& accept_value : accept_list->GetList()) {
+    if (!accept_value.is_string()) {
+      // A particular 'accept' entry is invalid - just drop that one entry.
+      AddErrorInfo("'accept' entry ignored, expected to be of type string.");
+      continue;
+    }
     accept_types.push_back(base::ASCIIToUTF16(accept_value.GetString()));
+  }
 
   return accept_types;
 }
@@ -409,26 +442,54 @@
 
   const base::ListValue* file_list = nullptr;
   if (!share_target_params.GetList("files", &file_list)) {
-    AddErrorInfo("property 'files' ignored, type array expected.");
+    // https://wicg.github.io/web-share-target/level-2/#share_target-member
+    // step 5 indicates that the 'files' attribute is allowed to be a single
+    // (non-array) ShareTargetFile.
+    const base::DictionaryValue* file_dictionary = nullptr;
+    if (!share_target_params.GetDictionary("files", &file_dictionary)) {
+      AddErrorInfo(
+          "property 'files' ignored, type array or ShareTargetFile expected.");
+      return files;
+    }
+
+    ParseShareTargetFile(*file_dictionary, &files);
+
     return files;
   }
 
   for (const base::Value& file_value : file_list->GetList()) {
     const base::DictionaryValue* file_dictionary = nullptr;
     if (!file_value.GetAsDictionary(&file_dictionary)) {
-      AddErrorInfo("files must be a sequence of non-empty file entires.");
+      AddErrorInfo("files must be a sequence of non-empty file entries.");
       continue;
     }
 
-    blink::Manifest::ShareTargetFile file;
-    file.name = ParseShareTargetFileName(*file_dictionary);
-    file.accept = ParseShareTargetFileAccept(*file_dictionary);
-    files.push_back(file);
+    ParseShareTargetFile(*file_dictionary, &files);
   }
 
   return files;
 }
 
+void ManifestParser::ParseShareTargetFile(
+    const base::DictionaryValue& file_dictionary,
+    std::vector<blink::Manifest::ShareTargetFile>* files) {
+  blink::Manifest::ShareTargetFile file;
+  file.name = ParseShareTargetFileName(file_dictionary);
+  if (file.name.empty()) {
+    // https://wicg.github.io/web-share-target/level-2/#share_target-member
+    // step 7.1 requires that we invalidate this ShareTargetFile if 'name' is an
+    // empty string. We also invalidate if 'name' is undefined or not a
+    // string.
+    return;
+  }
+
+  file.accept = ParseShareTargetFileAccept(file_dictionary);
+  if (file.accept.empty())
+    return;
+
+  files->push_back(file);
+}
+
 base::Optional<blink::Manifest::ShareTarget::Method>
 ManifestParser::ParseShareTargetMethod(
     const base::DictionaryValue& share_target_dict) {
diff --git a/content/renderer/manifest/manifest_parser.h b/content/renderer/manifest/manifest_parser.h
index dab5a09..a4e3f8e 100644
--- a/content/renderer/manifest/manifest_parser.h
+++ b/content/renderer/manifest/manifest_parser.h
@@ -144,10 +144,9 @@
   // Parses the 'purpose' field of an icon, as defined in:
   // https://w3c.github.io/manifest/#dfn-steps-for-processing-a-purpose-member-of-an-image
   // Returns a vector of Manifest::Icon::IconPurpose with the successfully
-  // parsed icon purposes, and a vector with Manifest::Icon::IconPurpose::Any if
-  // the parsing failed.
-  std::vector<blink::Manifest::ImageResource::Purpose> ParseIconPurpose(
-      const base::DictionaryValue& icon);
+  // parsed icon purposes, and nullopt if the parsing failed.
+  base::Optional<std::vector<blink::Manifest::ImageResource::Purpose>>
+  ParseIconPurpose(const base::DictionaryValue& icon);
 
   // Parses the 'icons' field of a Manifest, as defined in:
   // https://w3c.github.io/manifest/#dfn-steps-for-processing-an-array-of-images
@@ -162,8 +161,9 @@
   base::string16 ParseShareTargetFileName(const base::DictionaryValue& file);
 
   // Parses the accept field of a share target file, as defined in:
-  // https://github.com/WICG/web-share-target/blob/master/docs/interface.md
-  // Returns the parsed string if any, an empty string if the parsing failed.
+  // https://wicg.github.io/web-share-target/level-2/#sharetargetfiles-and-its-members
+  // Returns the vector of parsed strings if any, an empty vector if the parsing
+  // failed or no accept instances were provided.
   std::vector<base::string16> ParseShareTargetFileAccept(
       const base::DictionaryValue& file);
 
@@ -173,6 +173,12 @@
   std::vector<blink::Manifest::ShareTargetFile> ParseShareTargetFiles(
       const base::DictionaryValue& share_target_params);
 
+  // Parses a single ShareTargetFile (see above comment) and appends it to
+  // the given |files| vector.
+  void ParseShareTargetFile(
+      const base::DictionaryValue& file_dictionary,
+      std::vector<blink::Manifest::ShareTargetFile>* files);
+
   // Parses the method field of a Share Target, as defined in:
   // https://github.com/WICG/web-share-target/blob/master/docs/interface.md
   // Returns an optional share target method enum object..
@@ -186,7 +192,7 @@
       const base::DictionaryValue& share_target_dict);
 
   // Parses the 'params' field of a Share Target, as defined in:
-  // https://github.com/WICG/web-share-target/blob/master/docs/interface.md
+  // https://wicg.github.io/web-share-target/level-2/#sharetargetparams-and-its-members
   // Returns a parsed Manifest::ShareTargetParams, not all fields need to be
   // populated.
   blink::Manifest::ShareTargetParams ParseShareTargetParams(
diff --git a/content/renderer/manifest/manifest_parser_unittest.cc b/content/renderer/manifest/manifest_parser_unittest.cc
index d5a9330..fa1c9c1 100644
--- a/content/renderer/manifest/manifest_parser_unittest.cc
+++ b/content/renderer/manifest/manifest_parser_unittest.cc
@@ -904,8 +904,10 @@
   const std::string kPurposeParseStringError =
       "property 'purpose' ignored, type string expected.";
   const std::string kPurposeInvalidValueError =
-      "found icon with invalid purpose. "
-      "Using default value 'any'.";
+      "found icon with no valid purpose; ignoring it.";
+  const std::string kSomeInvalidPurposeError =
+      "found icon with one or more invalid purposes; those purposes are "
+      "ignored.";
 
   // Smoke test.
   {
@@ -1006,19 +1008,30 @@
   {
     blink::Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
-        "\"purpose\": \"badge notification\" } ] }");
+        "\"purpose\": \"badge fizzbuzz\" } ] }");
     ASSERT_EQ(manifest.icons[0].purpose.size(), 1u);
     EXPECT_EQ(manifest.icons[0].purpose[0],
               blink::Manifest::ImageResource::Purpose::BADGE);
     ASSERT_EQ(1u, GetErrorCount());
-    EXPECT_EQ(kPurposeInvalidValueError, errors()[0]);
+    EXPECT_EQ(kSomeInvalidPurposeError, errors()[0]);
   }
 
-  // 'any' is added when developer-supplied purpose is invalid.
+  // If developer-supplied purpose is invalid, entire icon is removed.
   {
     blink::Manifest manifest = ParseManifest(
         "{ \"icons\": [ {\"src\": \"\","
-        "\"purpose\": \"notification\" } ] }");
+        "\"purpose\": \"fizzbuzz\" } ] }");
+    ASSERT_EQ(0u, manifest.icons.size());
+    ASSERT_EQ(1u, GetErrorCount());
+    EXPECT_EQ(kPurposeInvalidValueError, errors()[0]);
+  }
+
+  // Two icons, one with an invalid purpose and the other normal.
+  {
+    blink::Manifest manifest = ParseManifest(
+        "{ \"icons\": [ {\"src\": \"\", \"purpose\": \"fizzbuzz\" }, "
+        "               {\"src\": \"\" }] }");
+    ASSERT_EQ(1u, manifest.icons.size());
     ASSERT_EQ(manifest.icons[0].purpose.size(), 1u);
     EXPECT_EQ(manifest.icons[0].purpose[0],
               blink::Manifest::ImageResource::Purpose::ANY);
@@ -1713,10 +1726,246 @@
         "}",
         manifest_url, document_url);
     EXPECT_TRUE(manifest.share_target.has_value());
-    EXPECT_EQ(manifest.share_target->params.files.size(), 1u);
-    EXPECT_EQ(manifest.share_target->params.files[0].accept.size(), 0u);
+    EXPECT_EQ(manifest.share_target->params.files.size(), 0u);
     EXPECT_EQ(0u, GetErrorCount());
   }
+
+  // Accept sequence contains non-string elements.
+  {
+    blink::Manifest manifest = ParseManifestWithURLs(
+        "{"
+        "  \"share_target\": {"
+        "    \"action\": \"https://foo.com/#\","
+        "    \"method\": \"POST\","
+        "    \"enctype\": \"multipart/form-data\","
+        "    \"params\": {"
+        "      \"title\": \"mytitle\","
+        "      \"files\": [{"
+        "        \"name\": \"name\","
+        "        \"accept\": [\"image/png\", 42]"
+        "      }]"
+        "    }"
+        "  }"
+        "}",
+        manifest_url, document_url);
+    const base::Optional<blink::Manifest::ShareTarget> share_target =
+        manifest.share_target;
+    EXPECT_TRUE(share_target.has_value());
+
+    const std::vector<blink::Manifest::ShareTargetFile>& files =
+        share_target->params.files;
+    EXPECT_EQ(1u, files.size());
+    EXPECT_TRUE(base::EqualsASCII(files.at(0).name, "name"));
+
+    const std::vector<base::string16>& accept = files.at(0).accept;
+    EXPECT_EQ(1u, accept.size());
+    EXPECT_TRUE(base::EqualsASCII(accept.at(0), "image/png"));
+
+    EXPECT_EQ(1u, GetErrorCount());
+    EXPECT_EQ("'accept' entry ignored, expected to be of type string.",
+              errors()[0]);
+  }
+
+  // Accept is just a single string.
+  {
+    blink::Manifest manifest = ParseManifestWithURLs(
+        "{"
+        "  \"share_target\": {"
+        "    \"action\": \"https://foo.com/#\","
+        "    \"method\": \"POST\","
+        "    \"enctype\": \"multipart/form-data\","
+        "    \"params\": {"
+        "      \"title\": \"mytitle\","
+        "      \"files\": [{"
+        "        \"name\": \"name\","
+        "        \"accept\": \"image/png\""
+        "      }]"
+        "    }"
+        "  }"
+        "}",
+        manifest_url, document_url);
+    const base::Optional<blink::Manifest::ShareTarget> share_target =
+        manifest.share_target;
+    EXPECT_TRUE(share_target.has_value());
+
+    const std::vector<blink::Manifest::ShareTargetFile>& files =
+        share_target->params.files;
+    EXPECT_EQ(1u, files.size());
+    EXPECT_TRUE(base::EqualsASCII(files.at(0).name, "name"));
+
+    const std::vector<base::string16>& accept = files.at(0).accept;
+    EXPECT_EQ(1u, accept.size());
+    EXPECT_TRUE(base::EqualsASCII(accept.at(0), "image/png"));
+    EXPECT_EQ(0u, GetErrorCount());
+  }
+
+  // Accept is neither a string nor an array of strings.
+  {
+    blink::Manifest manifest = ParseManifestWithURLs(
+        "{"
+        "  \"share_target\": {"
+        "    \"action\": \"https://foo.com/#\","
+        "    \"method\": \"POST\","
+        "    \"enctype\": \"multipart/form-data\","
+        "    \"params\": {"
+        "      \"title\": \"mytitle\","
+        "      \"files\": [{"
+        "        \"name\": \"name\","
+        "        \"accept\": true"
+        "      }]"
+        "    }"
+        "  }"
+        "}",
+        manifest_url, document_url);
+    const base::Optional<blink::Manifest::ShareTarget> share_target =
+        manifest.share_target;
+    EXPECT_TRUE(share_target.has_value());
+
+    const std::vector<blink::Manifest::ShareTargetFile>& files =
+        share_target->params.files;
+    EXPECT_EQ(0u, files.size());
+
+    EXPECT_EQ(1u, GetErrorCount());
+    EXPECT_EQ("property 'accept' ignored, type array or string expected.",
+              errors()[0]);
+  }
+
+  // Files is just a single ShareTargetFile (not an array).
+  {
+    blink::Manifest manifest = ParseManifestWithURLs(
+        "{"
+        "  \"share_target\": {"
+        "    \"action\": \"https://foo.com/#\","
+        "    \"method\": \"POST\","
+        "    \"enctype\": \"multipart/form-data\","
+        "    \"params\": {"
+        "      \"title\": \"mytitle\","
+        "      \"files\": {"
+        "        \"name\": \"name\","
+        "        \"accept\": \"image/png\""
+        "      }"
+        "    }"
+        "  }"
+        "}",
+        manifest_url, document_url);
+    EXPECT_TRUE(manifest.share_target.has_value());
+
+    const blink::Manifest::ShareTargetParams& params =
+        manifest.share_target->params;
+    EXPECT_EQ(1u, params.files.size());
+    EXPECT_TRUE(base::EqualsASCII(params.files.at(0).name, "name"));
+
+    const std::vector<base::string16>& accept = params.files.at(0).accept;
+    EXPECT_EQ(1u, accept.size());
+    EXPECT_TRUE(base::EqualsASCII(accept.at(0), "image/png"));
+    EXPECT_EQ(0u, GetErrorCount());
+  }
+
+  // Files is neither array nor ShareTargetFile.
+  {
+    blink::Manifest manifest = ParseManifestWithURLs(
+        "{"
+        "  \"share_target\": {"
+        "    \"action\": \"https://foo.com/#\","
+        "    \"method\": \"POST\","
+        "    \"enctype\": \"multipart/form-data\","
+        "    \"params\": {"
+        "      \"title\": \"mytitle\","
+        "      \"files\": 3"
+        "    }"
+        "  }"
+        "}",
+        manifest_url, document_url);
+    const base::Optional<blink::Manifest::ShareTarget> share_target =
+        manifest.share_target;
+    EXPECT_TRUE(share_target.has_value());
+
+    const std::vector<blink::Manifest::ShareTargetFile>& files =
+        share_target->params.files;
+    EXPECT_EQ(0u, files.size());
+
+    EXPECT_EQ(1u, GetErrorCount());
+    EXPECT_EQ(
+        "property 'files' ignored, type array or ShareTargetFile expected.",
+        errors()[0]);
+  }
+
+  // Files contains a non-dictionary entry.
+  {
+    blink::Manifest manifest = ParseManifestWithURLs(
+        "{"
+        "  \"share_target\": {"
+        "    \"action\": \"https://foo.com/#\","
+        "    \"method\": \"POST\","
+        "    \"enctype\": \"multipart/form-data\","
+        "    \"params\": {"
+        "      \"title\": \"mytitle\","
+        "      \"files\": ["
+        "        {"
+        "          \"name\": \"name\","
+        "          \"accept\": \"image/png\""
+        "        },"
+        "        3"
+        "      ]"
+        "    }"
+        "  }"
+        "}",
+        manifest_url, document_url);
+    const base::Optional<blink::Manifest::ShareTarget> share_target =
+        manifest.share_target;
+    EXPECT_TRUE(share_target.has_value());
+
+    const std::vector<blink::Manifest::ShareTargetFile>& files =
+        share_target->params.files;
+    EXPECT_EQ(1u, files.size());
+    EXPECT_TRUE(base::EqualsASCII(files.at(0).name, "name"));
+
+    const std::vector<base::string16>& accept = files.at(0).accept;
+    EXPECT_EQ(1u, accept.size());
+    EXPECT_TRUE(base::EqualsASCII(accept.at(0), "image/png"));
+
+    EXPECT_EQ(1u, GetErrorCount());
+    EXPECT_EQ("files must be a sequence of non-empty file entries.",
+              errors()[0]);
+  }
+
+  // Files contains empty file.
+  {
+    blink::Manifest manifest = ParseManifestWithURLs(
+        "{"
+        "  \"share_target\": {"
+        "    \"action\": \"https://foo.com/#\","
+        "    \"method\": \"POST\","
+        "    \"enctype\": \"multipart/form-data\","
+        "    \"params\": {"
+        "      \"title\": \"mytitle\","
+        "      \"files\": ["
+        "        {"
+        "          \"name\": \"name\","
+        "          \"accept\": \"image/png\""
+        "        },"
+        "        {}"
+        "      ]"
+        "    }"
+        "  }"
+        "}",
+        manifest_url, document_url);
+    const base::Optional<blink::Manifest::ShareTarget> share_target =
+        manifest.share_target;
+    EXPECT_TRUE(share_target.has_value());
+
+    const std::vector<blink::Manifest::ShareTargetFile>& files =
+        share_target->params.files;
+    EXPECT_EQ(1u, files.size());
+    EXPECT_TRUE(base::EqualsASCII(files.at(0).name, "name"));
+
+    const std::vector<base::string16>& accept = files.at(0).accept;
+    EXPECT_EQ(1u, accept.size());
+    EXPECT_TRUE(base::EqualsASCII(accept.at(0), "image/png"));
+
+    EXPECT_EQ(1u, GetErrorCount());
+    EXPECT_EQ("property 'name' missing.", errors()[0]);
+  }
 }
 
 TEST_F(ManifestParserTest, RelatedApplicationsParseRules) {
diff --git a/content/renderer/media/stream/media_stream_audio_processor.cc b/content/renderer/media/stream/media_stream_audio_processor.cc
index bad87fe..8f99a3a 100644
--- a/content/renderer/media/stream/media_stream_audio_processor.cc
+++ b/content/renderer/media/stream/media_stream_audio_processor.cc
@@ -806,11 +806,13 @@
   DCHECK_EQ(err, 0) << "ProcessStream() error: " << err;
 
   if (typing_detector_) {
-    webrtc::VoiceDetection* vad = ap->voice_detection();
-    DCHECK(vad->is_enabled());
-    bool detected = typing_detector_->Process(key_pressed,
-                                              vad->stream_has_voice());
-    base::subtle::Release_Store(&typing_detected_, detected);
+    // Ignore remote tracks to avoid unnecessary stats computation.
+    auto voice_detected =
+        ap->GetStatistics(false /* has_remote_tracks */).voice_detected;
+    DCHECK(voice_detected.has_value());
+    bool typing_detected =
+        typing_detector_->Process(key_pressed, *voice_detected);
+    base::subtle::Release_Store(&typing_detected_, typing_detected);
   }
 
   main_thread_runner_->PostTask(
diff --git a/content/renderer/media/stream/media_stream_audio_processor_options.cc b/content/renderer/media/stream/media_stream_audio_processor_options.cc
index 1fff770b..4f66483 100644
--- a/content/renderer/media/stream/media_stream_audio_processor_options.cc
+++ b/content/renderer/media/stream/media_stream_audio_processor_options.cc
@@ -139,10 +139,9 @@
 
 void EnableTypingDetection(AudioProcessing* audio_processing,
                            webrtc::TypingDetection* typing_detector) {
-  int err = audio_processing->voice_detection()->Enable(true);
-  err |= audio_processing->voice_detection()->set_likelihood(
-      webrtc::VoiceDetection::kVeryLowLikelihood);
-  CHECK_EQ(err, 0);
+  webrtc::AudioProcessing::Config apm_config = audio_processing->GetConfig();
+  apm_config.voice_detection.enabled = true;
+  audio_processing->ApplyConfig(apm_config);
 
   // Configure the update period to 1s (100 * 10ms) in the typing detector.
   typing_detector->SetParameters(0, 0, 0, 0, 0, 100);
diff --git a/content/renderer/media/stream/media_stream_audio_processor_unittest.cc b/content/renderer/media/stream/media_stream_audio_processor_unittest.cc
index ea10f58..b137d9e 100644
--- a/content/renderer/media/stream/media_stream_audio_processor_unittest.cc
+++ b/content/renderer/media/stream/media_stream_audio_processor_unittest.cc
@@ -158,8 +158,10 @@
     EXPECT_TRUE(config.echo_canceller.enabled);
 #if defined(OS_ANDROID)
     EXPECT_TRUE(config.echo_canceller.mobile_mode);
+    EXPECT_FALSE(config.voice_detection.enabled);
 #else
     EXPECT_FALSE(config.echo_canceller.mobile_mode);
+    EXPECT_TRUE(config.voice_detection.enabled);
 #endif
     EXPECT_TRUE(config.high_pass_filter.enabled);
 
@@ -170,13 +172,9 @@
 #if defined(OS_ANDROID)
     EXPECT_TRUE(audio_processing->gain_control()->mode() ==
         webrtc::GainControl::kFixedDigital);
-    EXPECT_FALSE(audio_processing->voice_detection()->is_enabled());
 #else
     EXPECT_TRUE(audio_processing->gain_control()->mode() ==
         webrtc::GainControl::kAdaptiveAnalog);
-    EXPECT_TRUE(audio_processing->voice_detection()->is_enabled());
-    EXPECT_TRUE(audio_processing->voice_detection()->likelihood() ==
-        webrtc::VoiceDetection::kVeryLowLikelihood);
 #endif
   }
 
diff --git a/content/renderer/navigation_state.cc b/content/renderer/navigation_state.cc
index 97b6a39..14a24825 100644
--- a/content/renderer/navigation_state.cc
+++ b/content/renderer/navigation_state.cc
@@ -17,18 +17,19 @@
     const CommonNavigationParams& common_params,
     const CommitNavigationParams& commit_params,
     base::TimeTicks time_commit_requested,
-    mojom::FrameNavigationControl::CommitNavigationCallback callback) {
-  return base::WrapUnique(new NavigationState(common_params, commit_params,
-                                              time_commit_requested, false,
-                                              std::move(callback)));
+    mojom::FrameNavigationControl::CommitNavigationCallback callback,
+    std::unique_ptr<NavigationClient> navigation_client) {
+  return base::WrapUnique(new NavigationState(
+      common_params, commit_params, time_commit_requested, false,
+      std::move(callback), std::move(navigation_client)));
 }
 
 // static
 std::unique_ptr<NavigationState> NavigationState::CreateContentInitiated() {
   return base::WrapUnique(new NavigationState(
       CommonNavigationParams(), CommitNavigationParams(), base::TimeTicks(),
-      true,
-      content::mojom::FrameNavigationControl::CommitNavigationCallback()));
+      true, content::mojom::FrameNavigationControl::CommitNavigationCallback(),
+      nullptr));
 }
 
 // static
@@ -57,14 +58,15 @@
     const CommitNavigationParams& commit_params,
     base::TimeTicks time_commit_requested,
     bool is_content_initiated,
-    mojom::FrameNavigationControl::CommitNavigationCallback callback)
+    mojom::FrameNavigationControl::CommitNavigationCallback callback,
+    std::unique_ptr<NavigationClient> navigation_client)
     : request_committed_(false),
       was_within_same_document_(false),
       is_content_initiated_(is_content_initiated),
       common_params_(common_params),
       commit_params_(commit_params),
       time_commit_requested_(time_commit_requested),
-      navigation_client_(nullptr),
+      navigation_client_(std::move(navigation_client)),
       commit_callback_(std::move(callback)) {}
 
 }  // namespace content
diff --git a/content/renderer/navigation_state.h b/content/renderer/navigation_state.h
index 95db5e1d..ea9ce006 100644
--- a/content/renderer/navigation_state.h
+++ b/content/renderer/navigation_state.h
@@ -27,7 +27,8 @@
       const CommonNavigationParams& common_params,
       const CommitNavigationParams& commit_params,
       base::TimeTicks time_commit_requested,
-      mojom::FrameNavigationControl::CommitNavigationCallback callback);
+      mojom::FrameNavigationControl::CommitNavigationCallback callback,
+      std::unique_ptr<NavigationClient> navigation_client);
 
   static std::unique_ptr<NavigationState> CreateContentInitiated();
 
@@ -74,8 +75,8 @@
       const CommitNavigationParams& commit_params,
       base::TimeTicks time_commit_requested,
       bool is_content_initiated,
-      content::mojom::FrameNavigationControl::CommitNavigationCallback
-          callback);
+      content::mojom::FrameNavigationControl::CommitNavigationCallback callback,
+      std::unique_ptr<NavigationClient> navigation_client);
 
   bool request_committed_;
   bool was_within_same_document_;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 9d61ea3..10ae35cf 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -493,26 +493,6 @@
   return request;
 }
 
-NavigationDownloadPolicy GetDownloadPolicy(
-    bool prevent_sandboxed_download,
-    bool is_opener_navigation,
-    const blink::WebURLRequest& request,
-    const WebSecurityOrigin& current_origin) {
-  if (prevent_sandboxed_download)
-    return NavigationDownloadPolicy::kDisallowSandbox;
-  if (!is_opener_navigation)
-    return NavigationDownloadPolicy::kAllow;
-  bool gesture = request.HasUserGesture();
-  bool cross_origin = !request.RequestorOrigin().CanAccess(current_origin);
-  if (!gesture && cross_origin)
-    return NavigationDownloadPolicy::kAllowOpenerCrossOriginNoGesture;
-  if (!gesture)
-    return NavigationDownloadPolicy::kAllowOpenerNoGesture;
-  if (cross_origin)
-    return NavigationDownloadPolicy::kAllowOpenerCrossOrigin;
-  return NavigationDownloadPolicy::kAllowOpener;
-}
-
 CommonNavigationParams MakeCommonNavigationParams(
     const WebSecurityOrigin& current_origin,
     std::unique_ptr<blink::WebNavigationInfo> info,
@@ -557,8 +537,10 @@
       static_cast<RequestExtraData*>(info->url_request.GetExtraData());
   DCHECK(extra_data);
   NavigationDownloadPolicy download_policy =
-      GetDownloadPolicy(prevent_sandboxed_download, info->is_opener_navigation,
-                        info->url_request, current_origin);
+      prevent_sandboxed_download
+          ? NavigationDownloadPolicy::kDisallowSandbox
+          : RenderFrameImpl::GetOpenerDownloadPolicy(
+                info->is_opener_navigation, info->url_request, current_origin);
   return CommonNavigationParams(
       info->url_request.Url(), info->url_request.RequestorOrigin(), referrer,
       extra_data->transition_type(), navigation_type, download_policy,
@@ -851,7 +833,8 @@
     const CommitNavigationParams& commit_params,
     base::TimeTicks time_commit_requested,
     mojom::FrameNavigationControl::CommitNavigationCallback commit_callback,
-    const network::ResourceResponseHead* head) {
+    const network::ResourceResponseHead* head,
+    std::unique_ptr<NavigationClient> navigation_client) {
   std::unique_ptr<DocumentState> document_state(new DocumentState());
   InternalDocumentStateData* internal_data =
       InternalDocumentStateData::FromDocumentState(document_state.get());
@@ -908,7 +891,7 @@
   InternalDocumentStateData::FromDocumentState(document_state.get())
       ->set_navigation_state(NavigationState::CreateBrowserInitiated(
           common_params, commit_params, time_commit_requested,
-          std::move(commit_callback)));
+          std::move(commit_callback), std::move(navigation_client)));
   return document_state;
 }
 
@@ -1618,6 +1601,24 @@
   return nullptr;
 }
 
+// static
+NavigationDownloadPolicy RenderFrameImpl::GetOpenerDownloadPolicy(
+    bool is_opener_navigation,
+    const blink::WebURLRequest& request,
+    const WebSecurityOrigin& current_origin) {
+  if (!is_opener_navigation)
+    return NavigationDownloadPolicy::kAllow;
+  bool gesture = request.HasUserGesture();
+  bool cross_origin = !request.RequestorOrigin().CanAccess(current_origin);
+  if (!gesture && cross_origin)
+    return NavigationDownloadPolicy::kAllowOpenerCrossOriginNoGesture;
+  if (!gesture)
+    return NavigationDownloadPolicy::kAllowOpenerNoGesture;
+  if (cross_origin)
+    return NavigationDownloadPolicy::kAllowOpenerCrossOrigin;
+  return NavigationDownloadPolicy::kAllowOpener;
+}
+
 blink::WebURL RenderFrameImpl::OverrideFlashEmbedWithHTML(
     const blink::WebURL& url) {
   return GetContentClient()->renderer()->OverrideFlashEmbedWithHTML(url);
@@ -2832,7 +2833,7 @@
     document_state = BuildDocumentStateFromParams(
         navigation_state->common_params(), navigation_state->commit_params(),
         base::TimeTicks(),  // Not used for failed navigation.
-        CommitNavigationCallback(), nullptr);
+        CommitNavigationCallback(), nullptr, nullptr);
     FillNavigationParams(navigation_state->common_params(),
                          navigation_state->commit_params(),
                          navigation_params.get());
@@ -3247,7 +3248,7 @@
     response_head = &head;
   std::unique_ptr<DocumentState> document_state(BuildDocumentStateFromParams(
       common_params, commit_params, base::TimeTicks::Now(), std::move(callback),
-      response_head));
+      response_head, std::move(navigation_client_impl_)));
 
   blink::WebFrameLoadType load_type = NavigationTypeToLoadType(
       common_params.navigation_type, common_params.should_replace_current_entry,
@@ -3480,7 +3481,7 @@
 
   std::unique_ptr<DocumentState> document_state = BuildDocumentStateFromParams(
       common_params, commit_params, base::TimeTicks(), std::move(callback),
-      nullptr);
+      nullptr, std::move(navigation_client_impl_));
 
   // The load of the error page can result in this frame being removed.
   // Use a WeakPtr as an easy way to detect whether this has occured. If so,
@@ -3542,7 +3543,7 @@
     internal_data->set_navigation_state(NavigationState::CreateBrowserInitiated(
         common_params, commit_params,
         base::TimeTicks(),  // Not used for same-document navigation.
-        CommitNavigationCallback()));
+        CommitNavigationCallback(), nullptr));
 
     // Load the request.
     commit_status = frame_->CommitSameDocumentNavigation(
@@ -6469,6 +6470,9 @@
     params.is_history_navigation_in_new_child = true;
 
   params.href_translate = info->href_translate.Latin1();
+  params.download_policy = RenderFrameImpl::GetOpenerDownloadPolicy(
+      info->is_opener_navigation, info->url_request,
+      frame_->GetSecurityOrigin());
 
   Send(new FrameHostMsg_OpenURL(routing_id_, params));
 }
@@ -6809,10 +6813,8 @@
                     : base::nullopt);
 
   mojom::NavigationClientAssociatedPtrInfo navigation_client_info;
-  if (IsPerNavigationMojoInterfaceEnabled()) {
+  if (IsPerNavigationMojoInterfaceEnabled())
     BindNavigationClient(mojo::MakeRequest(&navigation_client_info));
-    navigation_state->set_navigation_client(std::move(navigation_client_impl_));
-  }
 
   blink::mojom::NavigationInitiatorPtr initiator_ptr(
       blink::mojom::NavigationInitiatorPtrInfo(
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 68fb96be..6c9b951f 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -288,6 +288,15 @@
   // routing ID.
   static blink::WebFrame* ResolveOpener(int opener_frame_routing_id);
 
+  // Gets the download policy for a given navigation with regard to its opener
+  // status. We are trying to block downloads resulting from x-origin opener
+  // navigations if they do not have a gesture. See https://crbug.com/632514 for
+  // background.
+  static NavigationDownloadPolicy GetOpenerDownloadPolicy(
+      bool is_opener_navigation,
+      const blink::WebURLRequest& request,
+      const blink::WebSecurityOrigin& current_origin);
+
   // Overwrites the given URL to use an HTML5 embed if possible.
   blink::WebURL OverrideFlashEmbedWithHTML(const blink::WebURL& url) override;
 
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index c860bb6..75814f1 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -799,6 +799,7 @@
 
 void RenderFrameProxy::Navigate(const blink::WebURLRequest& request,
                                 bool should_replace_current_entry,
+                                bool is_opener_navigation,
                                 mojo::ScopedMessagePipeHandle blob_url_token) {
   // The request must always have a valid initiator origin.
   DCHECK(!request.RequestorOrigin().IsNull());
@@ -820,6 +821,8 @@
   params.triggering_event_info = blink::WebTriggeringEventInfo::kUnknown;
   params.blob_url_token = blob_url_token.release();
 
+  params.download_policy = RenderFrameImpl::GetOpenerDownloadPolicy(
+      is_opener_navigation, request, web_frame_->GetSecurityOrigin());
   Send(new FrameHostMsg_OpenURL(routing_id_, params));
 }
 
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index 7035422..a6bd961 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -201,6 +201,7 @@
                           bool has_user_gesture) override;
   void Navigate(const blink::WebURLRequest& request,
                 bool should_replace_current_entry,
+                bool is_opener_navigation,
                 mojo::ScopedMessagePipeHandle blob_url_token) override;
   void FrameRectsChanged(const blink::WebRect& local_frame_rect,
                          const blink::WebRect& screen_space_rect) override;
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.cc b/content/renderer/service_worker/service_worker_subresource_loader.cc
index 2ab6ad2..7718381 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader.cc
@@ -653,8 +653,8 @@
 // ServiceWorkerSubresourceLoader: URLLoader implementation -----------------
 
 void ServiceWorkerSubresourceLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>& removed_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
   TRACE_EVENT_WITH_FLOW1(
       "ServiceWorker", "ServiceWorkerSubresourceLoader::FollowRedirect",
@@ -665,7 +665,7 @@
   // TODO(arthursonzogni, juncai): This seems to be correctly implemented, but
   // not used so far. Add tests and remove this DCHECK to support this feature
   // if needed. See https://crbug.com/845683.
-  DCHECK(!removed_headers && !modified_headers)
+  DCHECK(removed_headers.empty() && modified_headers.IsEmpty())
       << "Redirect with removed or modified headers is not supported yet. See "
          "https://crbug.com/845683";
   DCHECK(!new_url.has_value()) << "Redirect with modified url was not "
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.h b/content/renderer/service_worker/service_worker_subresource_loader.h
index 0148819..1fe2aed 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.h
+++ b/content/renderer/service_worker/service_worker_subresource_loader.h
@@ -106,10 +106,9 @@
                      blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream);
 
   // network::mojom::URLLoader overrides:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>& removed_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int intra_priority_value) override;
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
index bb31aad..b3253536 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -1192,7 +1192,7 @@
 
   // Redirect once more.
   fake_controller_.RespondWithRedirect("https://other.example.com/baz.png");
-  loader->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+  loader->FollowRedirect({}, {}, base::nullopt);
   client->RunUntilRedirectReceived();
 
   EXPECT_EQ(net::OK, client->completion_status().error_code);
@@ -1211,7 +1211,7 @@
   mojo::DataPipe data_pipe;
   fake_controller_.RespondWithStream(mojo::MakeRequest(&stream_callback),
                                      std::move(data_pipe.consumer_handle));
-  loader->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+  loader->FollowRedirect({}, {}, base::nullopt);
   client->RunUntilResponseReceived();
 
   const network::ResourceResponseHead& info = client->response_head();
@@ -1281,7 +1281,7 @@
     redirect_location = std::string("https://www.example.com/redirect_") +
                         base::IntToString(count);
     fake_controller_.RespondWithRedirect(redirect_location);
-    loader->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+    loader->FollowRedirect({}, {}, base::nullopt);
   }
   client->RunUntilComplete();
 
diff --git a/content/shell/browser/web_test/web_test_permission_manager.cc b/content/shell/browser/web_test/web_test_permission_manager.cc
index f8cd7eca..6ce767c 100644
--- a/content/shell/browser/web_test/web_test_permission_manager.cc
+++ b/content/shell/browser/web_test/web_test_permission_manager.cc
@@ -43,11 +43,9 @@
 
 size_t WebTestPermissionManager::PermissionDescription::Hash::operator()(
     const PermissionDescription& description) const {
-  size_t hash =
-      BASE_HASH_NAMESPACE::hash<int>()(static_cast<int>(description.type));
-  hash += BASE_HASH_NAMESPACE::hash<std::string>()(
-      description.embedding_origin.spec());
-  hash += BASE_HASH_NAMESPACE::hash<std::string>()(description.origin.spec());
+  size_t hash = std::hash<int>()(static_cast<int>(description.type));
+  hash += std::hash<std::string>()(description.embedding_origin.spec());
+  hash += std::hash<std::string>()(description.origin.spec());
   return hash;
 }
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index d065315..da2868c 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -100,6 +100,8 @@
     "../public/test/mock_browsing_data_remover_delegate.h",
     "../public/test/mock_download_manager.cc",
     "../public/test/mock_download_manager.h",
+    "../public/test/mock_navigation_handle.cc",
+    "../public/test/mock_navigation_handle.h",
     "../public/test/mock_notification_observer.cc",
     "../public/test/mock_notification_observer.h",
     "../public/test/mock_permission_manager.cc",
diff --git a/content/test/test_navigation_url_loader.cc b/content/test/test_navigation_url_loader.cc
index 3980d3f..50fe67a 100644
--- a/content/test/test_navigation_url_loader.cc
+++ b/content/test/test_navigation_url_loader.cc
@@ -31,9 +31,8 @@
 }
 
 void TestNavigationURLLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers) {
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers) {
   redirect_count_++;
 }
 
diff --git a/content/test/test_navigation_url_loader.h b/content/test/test_navigation_url_loader.h
index a0da994..868511c9 100644
--- a/content/test/test_navigation_url_loader.h
+++ b/content/test/test_navigation_url_loader.h
@@ -35,10 +35,8 @@
                           NavigationURLLoaderDelegate* delegate);
 
   // NavigationURLLoader implementation.
-  void FollowRedirect(const base::Optional<std::vector<std::string>>&
-                          to_be_removed_request_headers,
-                      const base::Optional<net::HttpRequestHeaders>&
-                          modified_request_headers) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers) override;
   void ProceedWithResponse() override;
 
   NavigationRequestInfo* request_info() const { return request_info_.get(); }
diff --git a/extensions/browser/api/api_resource_manager.h b/extensions/browser/api/api_resource_manager.h
index b5ea217..a30b64fd 100644
--- a/extensions/browser/api/api_resource_manager.h
+++ b/extensions/browser/api/api_resource_manager.h
@@ -7,7 +7,9 @@
 
 #include <map>
 #include <memory>
+#include <string>
 #include <unordered_set>
+#include <utility>
 
 #include "base/containers/hash_tables.h"
 #include "base/memory/ptr_util.h"
@@ -35,7 +37,7 @@
 class BluetoothSocketApiFunction;
 class BluetoothSocketEventDispatcher;
 class SerialConnectFunction;
-class SerialEventDispatcher;
+class SerialPortManager;
 class TCPServerSocketEventDispatcher;
 class TCPSocketEventDispatcher;
 class UDPSocketEventDispatcher;
@@ -179,7 +181,7 @@
   friend class api::BluetoothSocketApiFunction;
   friend class api::BluetoothSocketEventDispatcher;
   friend class api::SerialConnectFunction;
-  friend class api::SerialEventDispatcher;
+  friend class api::SerialPortManager;
   friend class api::TCPServerSocketEventDispatcher;
   friend class api::TCPSocketEventDispatcher;
   friend class api::UDPSocketEventDispatcher;
diff --git a/extensions/browser/api/serial/BUILD.gn b/extensions/browser/api/serial/BUILD.gn
index edef4685..40be6ddc 100644
--- a/extensions/browser/api/serial/BUILD.gn
+++ b/extensions/browser/api/serial/BUILD.gn
@@ -13,8 +13,8 @@
     "serial_api.h",
     "serial_connection.cc",
     "serial_connection.h",
-    "serial_event_dispatcher.cc",
-    "serial_event_dispatcher.h",
+    "serial_port_manager.cc",
+    "serial_port_manager.h",
   ]
 
   deps = [
diff --git a/extensions/browser/api/serial/serial_api.cc b/extensions/browser/api/serial/serial_api.cc
index 9d246c4..b2b3e07b 100644
--- a/extensions/browser/api/serial/serial_api.cc
+++ b/extensions/browser/api/serial/serial_api.cc
@@ -5,20 +5,19 @@
 #include "extensions/browser/api/serial/serial_api.h"
 
 #include <algorithm>
+#include <map>
 #include <unordered_set>
-#include <vector>
+#include <utility>
 
 #include "base/task/post_task.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/common/service_manager_connection.h"
 #include "extensions/browser/api/serial/serial_connection.h"
-#include "extensions/browser/api/serial/serial_event_dispatcher.h"
+#include "extensions/browser/api/serial/serial_port_manager.h"
 #include "extensions/common/api/serial.h"
+#include "mojo/public/cpp/bindings/callback_helpers.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
-#include "services/device/public/mojom/constants.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
 
 using content::BrowserThread;
 
@@ -84,16 +83,11 @@
 
 ExtensionFunction::ResponseAction SerialGetDevicesFunction::Run() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(content::ServiceManagerConnection::GetForProcess());
-  content::ServiceManagerConnection::GetForProcess()
-      ->GetConnector()
-      ->BindInterface(device::mojom::kServiceName,
-                      mojo::MakeRequest(&port_manager_));
-  port_manager_.set_connection_error_handler(
-      base::BindOnce(&SerialGetDevicesFunction::OnGotDevices, this,
-                     std::vector<device::mojom::SerialPortInfoPtr>()));
-  port_manager_->GetDevices(
-      base::BindOnce(&SerialGetDevicesFunction::OnGotDevices, this));
+  auto* port_manager = SerialPortManager::Get(browser_context());
+  DCHECK(port_manager);
+  port_manager->GetDevices(mojo::WrapCallbackWithDefaultInvokeIfNotRun(
+      base::BindOnce(&SerialGetDevicesFunction::OnGotDevices, this),
+      std::vector<device::mojom::SerialPortInfoPtr>()));
   return RespondLater();
 }
 
@@ -103,7 +97,6 @@
       serial::GetDevices::Results::Create(
           mojo::ConvertTo<std::vector<serial::DeviceInfo>>(devices));
   Respond(ArgumentList(std::move(results)));
-  port_manager_.reset();
 }
 
 SerialConnectFunction::SerialConnectFunction() {}
@@ -134,16 +127,10 @@
     options->stop_bits = kDefaultStopBits;
 
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(content::ServiceManagerConnection::GetForProcess());
-  device::mojom::SerialPortManagerPtr port_manager;
-  content::ServiceManagerConnection::GetForProcess()
-      ->GetConnector()
-      ->BindInterface(device::mojom::kServiceName,
-                      mojo::MakeRequest(&port_manager));
-  port_manager->GetPort(params_->path, mojo::MakeRequest(&serial_port_info_));
-
-  serial_event_dispatcher_ = SerialEventDispatcher::Get(browser_context());
-  DCHECK(serial_event_dispatcher_);
+  serial_port_manager_ = SerialPortManager::Get(browser_context());
+  DCHECK(serial_port_manager_);
+  serial_port_manager_->GetPort(params_->path,
+                                mojo::MakeRequest(&serial_port_info_));
 
   return true;
 }
@@ -193,7 +180,7 @@
         manager_->data_, extension_->id(), id));
 
     info->connection_id = id;
-    serial_event_dispatcher_->PollConnection(extension_->id(), id);
+    serial_port_manager_->PollConnection(extension_->id(), id);
     results_ = serial::Connect::Results::Create(*info);
   }
   AsyncWorkCompleted();
@@ -319,8 +306,8 @@
   params_ = serial::SetPaused::Params::Create(*args_);
   EXTENSION_FUNCTION_VALIDATE(params_.get());
 
-  serial_event_dispatcher_ = SerialEventDispatcher::Get(browser_context());
-  DCHECK(serial_event_dispatcher_);
+  serial_port_manager_ = SerialPortManager::Get(browser_context());
+  DCHECK(serial_port_manager_);
   return true;
 }
 
@@ -334,8 +321,8 @@
   if (params_->paused != connection->paused()) {
     connection->set_paused(params_->paused);
     if (!params_->paused) {
-      serial_event_dispatcher_->PollConnection(extension_->id(),
-                                               params_->connection_id);
+      serial_port_manager_->PollConnection(extension_->id(),
+                                           params_->connection_id);
     }
   }
 
diff --git a/extensions/browser/api/serial/serial_api.h b/extensions/browser/api/serial/serial_api.h
index 6adefd74..a69f2eac 100644
--- a/extensions/browser/api/serial/serial_api.h
+++ b/extensions/browser/api/serial/serial_api.h
@@ -5,7 +5,9 @@
 #ifndef EXTENSIONS_BROWSER_API_SERIAL_SERIAL_API_H_
 #define EXTENSIONS_BROWSER_API_SERIAL_SERIAL_API_H_
 
+#include <memory>
 #include <string>
+#include <vector>
 
 #include "extensions/browser/api/api_resource_manager.h"
 #include "extensions/browser/api/async_api_function.h"
@@ -18,7 +20,7 @@
 
 namespace api {
 
-class SerialEventDispatcher;
+class SerialPortManager;
 
 class SerialAsyncApiFunction : public AsyncApiFunction {
  public:
@@ -52,8 +54,6 @@
  private:
   void OnGotDevices(std::vector<device::mojom::SerialPortInfoPtr> devices);
 
-  device::mojom::SerialPortManagerPtr port_manager_;
-
   DISALLOW_COPY_AND_ASSIGN(SerialGetDevicesFunction);
 };
 
@@ -78,8 +78,8 @@
 
   std::unique_ptr<serial::Connect::Params> params_;
 
-  // SerialEventDispatcher is owned by a BrowserContext.
-  SerialEventDispatcher* serial_event_dispatcher_;
+  // SerialPortManager is owned by a BrowserContext.
+  SerialPortManager* serial_port_manager_;
 
   // This connection is created within SerialConnectFunction.
   // From there its ownership is transferred to the
@@ -140,7 +140,7 @@
 
  private:
   std::unique_ptr<serial::SetPaused::Params> params_;
-  SerialEventDispatcher* serial_event_dispatcher_;
+  SerialPortManager* serial_port_manager_;
 };
 
 class SerialGetInfoFunction : public SerialAsyncApiFunction {
diff --git a/extensions/browser/api/serial/serial_apitest.cc b/extensions/browser/api/serial/serial_apitest.cc
index 6b460d5..be2c4bbd 100644
--- a/extensions/browser/api/serial/serial_apitest.cc
+++ b/extensions/browser/api/serial/serial_apitest.cc
@@ -2,12 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <map>
 #include <memory>
 #include <string>
 #include <utility>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/unguessable_token.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/api/serial/serial_api.h"
@@ -52,7 +54,7 @@
 
 class FakeSerialPort : public device::mojom::SerialPort {
  public:
-  FakeSerialPort(const std::string& path) : path_(path) {
+  explicit FakeSerialPort(const std::string& path) : path_(path) {
     options_.bitrate = 9600;
     options_.data_bits = device::mojom::SerialDataBits::EIGHT;
     options_.parity_bit = device::mojom::SerialParityBit::NO_PARITY;
@@ -169,28 +171,37 @@
 
 class FakeSerialPortManager : public device::mojom::SerialPortManager {
  public:
-  FakeSerialPortManager() = default;
+  FakeSerialPortManager() {
+    token_path_map_ = {
+        {base::UnguessableToken::Create(), "/dev/fakeserialmojo"},
+        {base::UnguessableToken::Create(), "\\\\COM800\\"}};
+  }
+
   ~FakeSerialPortManager() override = default;
 
  private:
   // device::mojom::SerialPortManager methods:
   void GetDevices(GetDevicesCallback callback) override {
     std::vector<device::mojom::SerialPortInfoPtr> devices;
-    auto device0 = device::mojom::SerialPortInfo::New();
-    device0->path = "/dev/fakeserialmojo";
-    auto device1 = device::mojom::SerialPortInfo::New();
-    device1->path = "\\\\COM800\\";
-    devices.push_back(std::move(device0));
-    devices.push_back(std::move(device1));
+    for (const auto& pair : token_path_map_) {
+      auto device = device::mojom::SerialPortInfo::New();
+      device->token = pair.first;
+      device->path = pair.second;
+      devices.push_back(std::move(device));
+    }
     std::move(callback).Run(std::move(devices));
   }
 
-  void GetPort(const std::string& path,
+  void GetPort(const base::UnguessableToken& token,
                device::mojom::SerialPortRequest request) override {
-    mojo::MakeStrongBinding(std::make_unique<FakeSerialPort>(path),
+    auto it = token_path_map_.find(token);
+    DCHECK(it != token_path_map_.end());
+    mojo::MakeStrongBinding(std::make_unique<FakeSerialPort>(it->second),
                             std::move(request));
   }
 
+  std::map<base::UnguessableToken, std::string> token_path_map_;
+
   DISALLOW_COPY_AND_ASSIGN(FakeSerialPortManager);
 };
 
diff --git a/extensions/browser/api/serial/serial_connection.h b/extensions/browser/api/serial/serial_connection.h
index 82912fb0..a97cfed 100644
--- a/extensions/browser/api/serial/serial_connection.h
+++ b/extensions/browser/api/serial/serial_connection.h
@@ -5,6 +5,7 @@
 #ifndef EXTENSIONS_BROWSER_API_SERIAL_SERIAL_CONNECTION_H_
 #define EXTENSIONS_BROWSER_API_SERIAL_SERIAL_CONNECTION_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
diff --git a/extensions/browser/api/serial/serial_event_dispatcher.cc b/extensions/browser/api/serial/serial_event_dispatcher.cc
deleted file mode 100644
index 9446d37..0000000
--- a/extensions/browser/api/serial/serial_event_dispatcher.cc
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/browser/api/serial/serial_event_dispatcher.h"
-
-#include <utility>
-
-#include "base/lazy_instance.h"
-#include "base/task/post_task.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "extensions/browser/api/serial/serial_connection.h"
-#include "extensions/browser/event_router.h"
-#include "extensions/browser/extensions_browser_client.h"
-
-namespace extensions {
-
-namespace api {
-
-namespace {
-
-bool ShouldPauseOnReceiveError(serial::ReceiveError error) {
-  return error == serial::RECEIVE_ERROR_DEVICE_LOST ||
-         error == serial::RECEIVE_ERROR_SYSTEM_ERROR ||
-         error == serial::RECEIVE_ERROR_DISCONNECTED ||
-         error == serial::RECEIVE_ERROR_BREAK ||
-         error == serial::RECEIVE_ERROR_FRAME_ERROR ||
-         error == serial::RECEIVE_ERROR_OVERRUN ||
-         error == serial::RECEIVE_ERROR_BUFFER_OVERFLOW ||
-         error == serial::RECEIVE_ERROR_PARITY_ERROR;
-}
-
-}  // namespace
-
-static base::LazyInstance<
-    BrowserContextKeyedAPIFactory<SerialEventDispatcher>>::DestructorAtExit
-    g_factory = LAZY_INSTANCE_INITIALIZER;
-
-// static
-BrowserContextKeyedAPIFactory<SerialEventDispatcher>*
-SerialEventDispatcher::GetFactoryInstance() {
-  return g_factory.Pointer();
-}
-
-// static
-SerialEventDispatcher* SerialEventDispatcher::Get(
-    content::BrowserContext* context) {
-  return BrowserContextKeyedAPIFactory<SerialEventDispatcher>::Get(context);
-}
-
-SerialEventDispatcher::SerialEventDispatcher(content::BrowserContext* context)
-    : thread_id_(SerialConnection::kThreadId), context_(context) {
-  ApiResourceManager<SerialConnection>* manager =
-      ApiResourceManager<SerialConnection>::Get(context_);
-  DCHECK(manager) << "No serial connection manager.";
-  connections_ = manager->data_;
-}
-
-SerialEventDispatcher::~SerialEventDispatcher() {
-}
-
-SerialEventDispatcher::ReceiveParams::ReceiveParams() {
-}
-
-SerialEventDispatcher::ReceiveParams::ReceiveParams(
-    const ReceiveParams& other) = default;
-
-SerialEventDispatcher::ReceiveParams::~ReceiveParams() {
-}
-
-void SerialEventDispatcher::PollConnection(const std::string& extension_id,
-                                           int connection_id) {
-  DCHECK_CURRENTLY_ON(thread_id_);
-
-  ReceiveParams params;
-  params.thread_id = thread_id_;
-  params.browser_context_id = context_;
-  params.extension_id = extension_id;
-  params.connections = connections_;
-  params.connection_id = connection_id;
-
-  StartReceive(params);
-}
-
-// static
-void SerialEventDispatcher::StartReceive(const ReceiveParams& params) {
-  DCHECK_CURRENTLY_ON(params.thread_id);
-
-  SerialConnection* connection =
-      params.connections->Get(params.extension_id, params.connection_id);
-  if (!connection)
-    return;
-  DCHECK(params.extension_id == connection->owner_extension_id());
-
-  if (connection->paused())
-    return;
-
-  connection->Receive(base::BindOnce(&ReceiveCallback, params));
-}
-
-// static
-void SerialEventDispatcher::ReceiveCallback(const ReceiveParams& params,
-                                            std::vector<uint8_t> data,
-                                            serial::ReceiveError error) {
-  DCHECK_CURRENTLY_ON(params.thread_id);
-
-  // Note that an error (e.g. timeout) does not necessarily mean that no data
-  // was read, so we may fire an onReceive regardless of any error code.
-  if (data.size() > 0) {
-    serial::ReceiveInfo receive_info;
-    receive_info.connection_id = params.connection_id;
-    receive_info.data = std::move(data);
-    std::unique_ptr<base::ListValue> args =
-        serial::OnReceive::Create(receive_info);
-    std::unique_ptr<extensions::Event> event(
-        new extensions::Event(extensions::events::SERIAL_ON_RECEIVE,
-                              serial::OnReceive::kEventName, std::move(args)));
-    PostEvent(params, std::move(event));
-  }
-
-  if (error != serial::RECEIVE_ERROR_NONE) {
-    serial::ReceiveErrorInfo error_info;
-    error_info.connection_id = params.connection_id;
-    error_info.error = error;
-    std::unique_ptr<base::ListValue> args =
-        serial::OnReceiveError::Create(error_info);
-    std::unique_ptr<extensions::Event> event(new extensions::Event(
-        extensions::events::SERIAL_ON_RECEIVE_ERROR,
-        serial::OnReceiveError::kEventName, std::move(args)));
-    PostEvent(params, std::move(event));
-    if (ShouldPauseOnReceiveError(error)) {
-      SerialConnection* connection =
-          params.connections->Get(params.extension_id, params.connection_id);
-      if (connection)
-        connection->set_paused(true);
-    }
-  }
-
-  // Queue up the next read operation.
-  base::PostTaskWithTraits(FROM_HERE, {params.thread_id},
-                           base::BindOnce(&StartReceive, params));
-}
-
-// static
-void SerialEventDispatcher::PostEvent(
-    const ReceiveParams& params,
-    std::unique_ptr<extensions::Event> event) {
-  DCHECK_CURRENTLY_ON(params.thread_id);
-
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(&DispatchEvent, params.browser_context_id,
-                     params.extension_id, std::move(event)));
-}
-
-// static
-void SerialEventDispatcher::DispatchEvent(
-    void* browser_context_id,
-    const std::string& extension_id,
-    std::unique_ptr<extensions::Event> event) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  content::BrowserContext* context =
-      reinterpret_cast<content::BrowserContext*>(browser_context_id);
-  if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context))
-    return;
-
-  EventRouter* router = EventRouter::Get(context);
-  if (router)
-    router->DispatchEventToExtension(extension_id, std::move(event));
-}
-
-}  // namespace api
-
-}  // namespace extensions
diff --git a/extensions/browser/api/serial/serial_event_dispatcher.h b/extensions/browser/api/serial/serial_event_dispatcher.h
deleted file mode 100644
index 63b863eb..0000000
--- a/extensions/browser/api/serial/serial_event_dispatcher.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef EXTENSIONS_BROWSER_API_SERIAL_SERIAL_EVENT_DISPATCHER_H_
-#define EXTENSIONS_BROWSER_API_SERIAL_SERIAL_EVENT_DISPATCHER_H_
-
-#include <string>
-#include <vector>
-
-#include "content/public/browser/browser_thread.h"
-#include "extensions/browser/api/api_resource_manager.h"
-#include "extensions/common/api/serial.h"
-
-namespace content {
-class BrowserContext;
-}
-
-namespace extensions {
-
-struct Event;
-class SerialConnection;
-
-namespace api {
-
-// Per-browser-context dispatcher for events on serial connections.
-class SerialEventDispatcher : public BrowserContextKeyedAPI {
- public:
-  explicit SerialEventDispatcher(content::BrowserContext* context);
-  ~SerialEventDispatcher() override;
-
-  // Start receiving data and firing events for a connection.
-  void PollConnection(const std::string& extension_id, int connection_id);
-
-  static SerialEventDispatcher* Get(content::BrowserContext* context);
-
-  // BrowserContextKeyedAPI implementation.
-  static BrowserContextKeyedAPIFactory<SerialEventDispatcher>*
-      GetFactoryInstance();
-
- private:
-  typedef ApiResourceManager<SerialConnection>::ApiResourceData ConnectionData;
-  friend class BrowserContextKeyedAPIFactory<SerialEventDispatcher>;
-
-  // BrowserContextKeyedAPI implementation.
-  static const char* service_name() { return "SerialEventDispatcher"; }
-  static const bool kServiceHasOwnInstanceInIncognito = true;
-  static const bool kServiceIsNULLWhileTesting = true;
-
-  struct ReceiveParams {
-    ReceiveParams();
-    ReceiveParams(const ReceiveParams& other);
-    ~ReceiveParams();
-
-    content::BrowserThread::ID thread_id;
-    void* browser_context_id;
-    std::string extension_id;
-    scoped_refptr<ConnectionData> connections;
-    int connection_id;
-  };
-
-  static void StartReceive(const ReceiveParams& params);
-
-  static void ReceiveCallback(const ReceiveParams& params,
-                              std::vector<uint8_t> data,
-                              serial::ReceiveError error);
-
-  static void PostEvent(const ReceiveParams& params,
-                        std::unique_ptr<extensions::Event> event);
-
-  static void DispatchEvent(void* browser_context_id,
-                            const std::string& extension_id,
-                            std::unique_ptr<extensions::Event> event);
-
-  content::BrowserThread::ID thread_id_;
-  content::BrowserContext* const context_;
-  scoped_refptr<ConnectionData> connections_;
-};
-
-}  // namespace api
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_BROWSER_API_SERIAL_SERIAL_EVENT_DISPATCHER_H_
diff --git a/extensions/browser/api/serial/serial_port_manager.cc b/extensions/browser/api/serial/serial_port_manager.cc
new file mode 100644
index 0000000..e8e22ec
--- /dev/null
+++ b/extensions/browser/api/serial/serial_port_manager.cc
@@ -0,0 +1,224 @@
+// Copyright 2018 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 "extensions/browser/api/serial/serial_port_manager.h"
+
+#include <utility>
+
+#include "base/lazy_instance.h"
+#include "base/task/post_task.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/service_manager_connection.h"
+#include "extensions/browser/api/serial/serial_connection.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/extensions_browser_client.h"
+#include "services/device/public/mojom/constants.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace extensions {
+
+namespace api {
+
+namespace {
+
+bool ShouldPauseOnReceiveError(serial::ReceiveError error) {
+  return error == serial::RECEIVE_ERROR_DEVICE_LOST ||
+         error == serial::RECEIVE_ERROR_SYSTEM_ERROR ||
+         error == serial::RECEIVE_ERROR_DISCONNECTED ||
+         error == serial::RECEIVE_ERROR_BREAK ||
+         error == serial::RECEIVE_ERROR_FRAME_ERROR ||
+         error == serial::RECEIVE_ERROR_OVERRUN ||
+         error == serial::RECEIVE_ERROR_BUFFER_OVERFLOW ||
+         error == serial::RECEIVE_ERROR_PARITY_ERROR;
+}
+
+}  // namespace
+
+static base::LazyInstance<BrowserContextKeyedAPIFactory<SerialPortManager>>::
+    DestructorAtExit g_factory = LAZY_INSTANCE_INITIALIZER;
+
+// static
+BrowserContextKeyedAPIFactory<SerialPortManager>*
+SerialPortManager::GetFactoryInstance() {
+  return g_factory.Pointer();
+}
+
+// static
+SerialPortManager* SerialPortManager::Get(content::BrowserContext* context) {
+  return BrowserContextKeyedAPIFactory<SerialPortManager>::Get(context);
+}
+
+SerialPortManager::SerialPortManager(content::BrowserContext* context)
+    : thread_id_(SerialConnection::kThreadId),
+      context_(context),
+      weak_factory_(this) {
+  ApiResourceManager<SerialConnection>* manager =
+      ApiResourceManager<SerialConnection>::Get(context_);
+  DCHECK(manager) << "No serial connection manager.";
+  connections_ = manager->data_;
+}
+
+SerialPortManager::~SerialPortManager() {}
+
+SerialPortManager::ReceiveParams::ReceiveParams() {}
+
+SerialPortManager::ReceiveParams::ReceiveParams(const ReceiveParams& other) =
+    default;
+
+SerialPortManager::ReceiveParams::~ReceiveParams() {}
+
+void SerialPortManager::GetDevices(
+    device::mojom::SerialPortManager::GetDevicesCallback callback) {
+  EnsureConnection();
+  port_manager_->GetDevices(std::move(callback));
+}
+
+void SerialPortManager::GetPort(const std::string& path,
+                                device::mojom::SerialPortRequest request) {
+  EnsureConnection();
+  port_manager_->GetDevices(
+      base::BindOnce(&SerialPortManager::OnGotDevicesToGetPort,
+                     weak_factory_.GetWeakPtr(), path, std::move(request)));
+}
+
+void SerialPortManager::PollConnection(const std::string& extension_id,
+                                       int connection_id) {
+  DCHECK_CURRENTLY_ON(thread_id_);
+
+  ReceiveParams params;
+  params.thread_id = thread_id_;
+  params.browser_context_id = context_;
+  params.extension_id = extension_id;
+  params.connections = connections_;
+  params.connection_id = connection_id;
+
+  StartReceive(params);
+}
+
+// static
+void SerialPortManager::StartReceive(const ReceiveParams& params) {
+  DCHECK_CURRENTLY_ON(params.thread_id);
+
+  SerialConnection* connection =
+      params.connections->Get(params.extension_id, params.connection_id);
+  if (!connection)
+    return;
+  DCHECK(params.extension_id == connection->owner_extension_id());
+
+  if (connection->paused())
+    return;
+
+  connection->Receive(base::BindOnce(&ReceiveCallback, params));
+}
+
+// static
+void SerialPortManager::ReceiveCallback(const ReceiveParams& params,
+                                        std::vector<uint8_t> data,
+                                        serial::ReceiveError error) {
+  DCHECK_CURRENTLY_ON(params.thread_id);
+
+  // Note that an error (e.g. timeout) does not necessarily mean that no data
+  // was read, so we may fire an onReceive regardless of any error code.
+  if (data.size() > 0) {
+    serial::ReceiveInfo receive_info;
+    receive_info.connection_id = params.connection_id;
+    receive_info.data = std::move(data);
+    std::unique_ptr<base::ListValue> args =
+        serial::OnReceive::Create(receive_info);
+    std::unique_ptr<extensions::Event> event(
+        new extensions::Event(extensions::events::SERIAL_ON_RECEIVE,
+                              serial::OnReceive::kEventName, std::move(args)));
+    PostEvent(params, std::move(event));
+  }
+
+  if (error != serial::RECEIVE_ERROR_NONE) {
+    serial::ReceiveErrorInfo error_info;
+    error_info.connection_id = params.connection_id;
+    error_info.error = error;
+    std::unique_ptr<base::ListValue> args =
+        serial::OnReceiveError::Create(error_info);
+    std::unique_ptr<extensions::Event> event(new extensions::Event(
+        extensions::events::SERIAL_ON_RECEIVE_ERROR,
+        serial::OnReceiveError::kEventName, std::move(args)));
+    PostEvent(params, std::move(event));
+    if (ShouldPauseOnReceiveError(error)) {
+      SerialConnection* connection =
+          params.connections->Get(params.extension_id, params.connection_id);
+      if (connection)
+        connection->set_paused(true);
+    }
+  }
+
+  // Queue up the next read operation.
+  base::PostTaskWithTraits(FROM_HERE, {params.thread_id},
+                           base::BindOnce(&StartReceive, params));
+}
+
+// static
+void SerialPortManager::PostEvent(const ReceiveParams& params,
+                                  std::unique_ptr<extensions::Event> event) {
+  DCHECK_CURRENTLY_ON(params.thread_id);
+
+  base::PostTaskWithTraits(
+      FROM_HERE, {BrowserThread::UI},
+      base::BindOnce(&DispatchEvent, params.browser_context_id,
+                     params.extension_id, std::move(event)));
+}
+
+// static
+void SerialPortManager::DispatchEvent(
+    void* browser_context_id,
+    const std::string& extension_id,
+    std::unique_ptr<extensions::Event> event) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  content::BrowserContext* context =
+      reinterpret_cast<content::BrowserContext*>(browser_context_id);
+  if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context))
+    return;
+
+  EventRouter* router = EventRouter::Get(context);
+  if (router)
+    router->DispatchEventToExtension(extension_id, std::move(event));
+}
+
+void SerialPortManager::EnsureConnection() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  if (port_manager_)
+    return;
+
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(content::ServiceManagerConnection::GetForProcess());
+  content::ServiceManagerConnection::GetForProcess()
+      ->GetConnector()
+      ->BindInterface(device::mojom::kServiceName,
+                      mojo::MakeRequest(&port_manager_));
+  port_manager_.set_connection_error_handler(
+      base::BindOnce(&SerialPortManager::OnPortManagerConnectionError,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void SerialPortManager::OnGotDevicesToGetPort(
+    const std::string& path,
+    device::mojom::SerialPortRequest request,
+    std::vector<device::mojom::SerialPortInfoPtr> devices) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  for (auto& device : devices) {
+    if (device->path == path) {
+      port_manager_->GetPort(device->token, std::move(request));
+      return;
+    }
+  }
+}
+
+void SerialPortManager::OnPortManagerConnectionError() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  port_manager_.reset();
+}
+
+}  // namespace api
+
+}  // namespace extensions
diff --git a/extensions/browser/api/serial/serial_port_manager.h b/extensions/browser/api/serial/serial_port_manager.h
new file mode 100644
index 0000000..502c221f
--- /dev/null
+++ b/extensions/browser/api/serial/serial_port_manager.h
@@ -0,0 +1,105 @@
+// Copyright 2018 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 EXTENSIONS_BROWSER_API_SERIAL_SERIAL_PORT_MANAGER_H_
+#define EXTENSIONS_BROWSER_API_SERIAL_SERIAL_PORT_MANAGER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/threading/thread_checker.h"
+#include "content/public/browser/browser_thread.h"
+#include "extensions/browser/api/api_resource_manager.h"
+#include "extensions/browser/browser_context_keyed_api_factory.h"
+#include "extensions/common/api/serial.h"
+#include "services/device/public/mojom/serial.mojom.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace extensions {
+
+struct Event;
+class SerialConnection;
+
+namespace api {
+// Per-browser-context dispatcher for events on serial connections.
+class SerialPortManager : public BrowserContextKeyedAPI {
+ public:
+  static SerialPortManager* Get(content::BrowserContext* context);
+
+  // BrowserContextKeyedAPI implementation.
+  static BrowserContextKeyedAPIFactory<SerialPortManager>* GetFactoryInstance();
+
+  explicit SerialPortManager(content::BrowserContext* context);
+  ~SerialPortManager() override;
+
+  void GetDevices(
+      device::mojom::SerialPortManager::GetDevicesCallback callback);
+
+  void GetPort(const std::string& path,
+               device::mojom::SerialPortRequest request);
+
+  // Start receiving data and firing events for a connection.
+  void PollConnection(const std::string& extension_id, int connection_id);
+
+ private:
+  typedef ApiResourceManager<SerialConnection>::ApiResourceData ConnectionData;
+  friend class BrowserContextKeyedAPIFactory<SerialPortManager>;
+
+  // BrowserContextKeyedAPI implementation.
+  static const char* service_name() { return "SerialPortManager"; }
+  static const bool kServiceHasOwnInstanceInIncognito = true;
+  static const bool kServiceIsNULLWhileTesting = true;
+
+  struct ReceiveParams {
+    ReceiveParams();
+    ReceiveParams(const ReceiveParams& other);
+    ~ReceiveParams();
+
+    content::BrowserThread::ID thread_id;
+    void* browser_context_id;
+    std::string extension_id;
+    scoped_refptr<ConnectionData> connections;
+    int connection_id;
+  };
+
+  static void StartReceive(const ReceiveParams& params);
+
+  static void ReceiveCallback(const ReceiveParams& params,
+                              std::vector<uint8_t> data,
+                              serial::ReceiveError error);
+
+  static void PostEvent(const ReceiveParams& params,
+                        std::unique_ptr<extensions::Event> event);
+
+  static void DispatchEvent(void* browser_context_id,
+                            const std::string& extension_id,
+                            std::unique_ptr<extensions::Event> event);
+
+  void EnsureConnection();
+  void OnGotDevicesToGetPort(
+      const std::string& path,
+      device::mojom::SerialPortRequest request,
+      std::vector<device::mojom::SerialPortInfoPtr> devices);
+  void OnPortManagerConnectionError();
+
+  device::mojom::SerialPortManagerPtr port_manager_;
+  content::BrowserThread::ID thread_id_;
+  scoped_refptr<ConnectionData> connections_;
+  content::BrowserContext* const context_;
+
+  THREAD_CHECKER(thread_checker_);
+  base::WeakPtrFactory<SerialPortManager> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(SerialPortManager);
+};
+
+}  // namespace api
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_SERIAL_SERIAL_PORT_MANAGER_H_
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
index 80d7752..dbcb0fba 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -128,21 +128,15 @@
 }
 
 void WebRequestProxyingURLLoaderFactory::InProgressRequest::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
-  if (to_be_removed_request_headers) {
-    for (const std::string& header : *to_be_removed_request_headers)
-      request_.headers.RemoveHeader(header);
-  }
-
-  if (modified_request_headers)
-    request_.headers.MergeFrom(*modified_request_headers);
+  for (const std::string& header : removed_headers)
+    request_.headers.RemoveHeader(header);
+  request_.headers.MergeFrom(modified_headers);
 
   if (target_loader_.is_bound()) {
-    target_loader_->FollowRedirect(to_be_removed_request_headers,
-                                   modified_request_headers, new_url);
+    target_loader_->FollowRedirect(removed_headers, modified_headers, new_url);
   }
 
   Restart();
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
index 23950345..1ca71ad 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
@@ -65,11 +65,9 @@
     void Restart();
 
     // network::mojom::URLLoader:
-    void FollowRedirect(
-        const base::Optional<std::vector<std::string>>&
-            to_be_removed_request_headers,
-        const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-        const base::Optional<GURL>& new_url) override;
+    void FollowRedirect(const std::vector<std::string>& removed_headers,
+                        const net::HttpRequestHeaders& modified_headers,
+                        const base::Optional<GURL>& new_url) override;
     void ProceedWithResponse() override;
     void SetPriority(net::RequestPriority priority,
                      int32_t intra_priority_value) override;
diff --git a/extensions/browser/api/webcam_private/visca_webcam.cc b/extensions/browser/api/webcam_private/visca_webcam.cc
index 8a81610..307f89fc 100644
--- a/extensions/browser/api/webcam_private/visca_webcam.cc
+++ b/extensions/browser/api/webcam_private/visca_webcam.cc
@@ -6,7 +6,8 @@
 
 #include <stddef.h>
 #include <stdint.h>
-#include <utility>
+
+#include <algorithm>
 
 #include "base/bind.h"
 #include "base/location.h"
@@ -16,10 +17,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/common/service_manager_connection.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
-#include "services/device/public/mojom/constants.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
 
 using content::BrowserThread;
 
@@ -167,18 +165,9 @@
 ViscaWebcam::~ViscaWebcam() {
 }
 
-void ViscaWebcam::Open(const std::string& path,
-                       const std::string& extension_id,
+void ViscaWebcam::Open(const std::string& extension_id,
+                       device::mojom::SerialPortPtrInfo port_ptr_info,
                        const OpenCompleteCallback& open_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  device::mojom::SerialPortManagerPtr port_manager;
-  device::mojom::SerialPortPtrInfo port_ptr_info;
-  DCHECK(content::ServiceManagerConnection::GetForProcess());
-  content::ServiceManagerConnection::GetForProcess()
-      ->GetConnector()
-      ->BindInterface(device::mojom::kServiceName,
-                      mojo::MakeRequest(&port_manager));
-  port_manager->GetPort(path, mojo::MakeRequest(&port_ptr_info));
   base::PostTaskWithTraits(
       FROM_HERE, {BrowserThread::IO},
       base::Bind(&ViscaWebcam::OpenOnIOThread, weak_ptr_factory_.GetWeakPtr(),
diff --git a/extensions/browser/api/webcam_private/visca_webcam.h b/extensions/browser/api/webcam_private/visca_webcam.h
index bb5e2051..77c7d223 100644
--- a/extensions/browser/api/webcam_private/visca_webcam.h
+++ b/extensions/browser/api/webcam_private/visca_webcam.h
@@ -5,6 +5,11 @@
 #ifndef EXTENSIONS_BROWSER_API_WEBCAM_PRIVATE_VISCA_WEBCAM_H_
 #define EXTENSIONS_BROWSER_API_WEBCAM_PRIVATE_VISCA_WEBCAM_H_
 
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
 #include "base/callback.h"
 #include "base/containers/circular_deque.h"
 #include "base/macros.h"
@@ -26,8 +31,8 @@
   // steps (in order): 1. Open the serial port; 2. Request address; 3. Clear the
   // command buffer. After these three steps completes, |open_callback| will be
   // called.
-  void Open(const std::string& path,
-            const std::string& extension_id,
+  void Open(const std::string& extension_id,
+            device::mojom::SerialPortPtrInfo port_ptr_info,
             const OpenCompleteCallback& open_callback);
 
  private:
diff --git a/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc b/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
index 76dcfdd..496d72a 100644
--- a/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
+++ b/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
@@ -8,6 +8,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/media_device_id.h"
 #include "content/public/browser/resource_context.h"
+#include "extensions/browser/api/serial/serial_port_manager.h"
 #include "extensions/browser/api/webcam_private/v4l2_webcam.h"
 #include "extensions/browser/api/webcam_private/visca_webcam.h"
 #include "extensions/browser/process_manager.h"
@@ -77,9 +78,15 @@
   if (webcam_resource)
     return false;
 
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  device::mojom::SerialPortPtrInfo port_ptr_info;
+  auto* port_manager = api::SerialPortManager::Get(browser_context_);
+  DCHECK(port_manager);
+  port_manager->GetPort(device_path, mojo::MakeRequest(&port_ptr_info));
+
   ViscaWebcam* visca_webcam = new ViscaWebcam;
   visca_webcam->Open(
-      device_path, extension_id,
+      extension_id, std::move(port_ptr_info),
       base::Bind(&WebcamPrivateAPI::OnOpenSerialWebcam,
                  weak_ptr_factory_.GetWeakPtr(), extension_id, device_path,
                  base::WrapRefCounted(visca_webcam), callback));
diff --git a/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js b/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
index 80d64a0e..3fe5fe6 100644
--- a/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
+++ b/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
@@ -5,6 +5,7 @@
 // This module implements helper objects for the dialog, newwindow, and
 // permissionrequest <webview> events.
 
+var logging = requireNative('logging');
 var MessagingNatives = requireNative('messaging_natives');
 var WebViewConstants = require('webViewConstants').WebViewConstants;
 var WebViewInternal = getInternalApi ?
@@ -19,6 +20,15 @@
                         'filesystem',
                         'fullscreen'];
 
+// The browser will kill us if we send it a bad instance ID.
+// TODO(780728): Remove once the cause of the bad ID is known.
+function CrashIfInvalidInstanceId(instanceId, culpritFunction) {
+  logging.CHECK(
+      instanceId > 0,
+      'WebView: Invalid instance ID (' + instanceId + ') from ' +
+          culpritFunction);
+}
+
 // -----------------------------------------------------------------------------
 // WebViewActionRequest object.
 
@@ -55,6 +65,8 @@
   }
 
   this.actionTaken = true;
+  CrashIfInvalidInstanceId(
+      this.guestInstanceId, 'WebViewActionRequest.defaultAction');
   WebViewInternal.setPermission(this.guestInstanceId, this.requestId, 'default',
                                 '', $Function.bind(function(allowed) {
     if (allowed) {
@@ -128,11 +140,13 @@
     ok: $Function.bind(function(user_input) {
       this.validateCall();
       user_input = user_input || '';
+      CrashIfInvalidInstanceId(this.guestInstanceId, 'Dialog ok');
       WebViewInternal.setPermission(
           this.guestInstanceId, this.requestId, 'allow', user_input);
     }, this),
     cancel: $Function.bind(function() {
       this.validateCall();
+      CrashIfInvalidInstanceId(this.guestInstanceId, 'Dialog cancel');
       WebViewInternal.setPermission(
           this.guestInstanceId, this.requestId, 'deny');
     }, this)
@@ -197,6 +211,7 @@
       // then we will fail and it will be treated as if the new window
       // was rejected. The permission API plumbing is used here to clean
       // up the state created for the new window if attaching fails.
+      CrashIfInvalidInstanceId(this.guestInstanceId, 'NewWindow attach');
       WebViewInternal.setPermission(this.guestInstanceId, this.requestId,
                                     attached ? 'allow' : 'deny');
     }, this),
@@ -207,6 +222,7 @@
         // guestInstanceId.
         return;
       }
+      CrashIfInvalidInstanceId(this.guestInstanceId, 'NewWindow discard');
       WebViewInternal.setPermission(
           this.guestInstanceId, this.requestId, 'deny');
     }, this)
@@ -237,11 +253,13 @@
 
 PermissionRequest.prototype.allow = function() {
   this.validateCall();
+  CrashIfInvalidInstanceId(this.guestInstanceId, 'PermissionRequest.allow');
   WebViewInternal.setPermission(this.guestInstanceId, this.requestId, 'allow');
 };
 
 PermissionRequest.prototype.deny = function() {
   this.validateCall();
+  CrashIfInvalidInstanceId(this.guestInstanceId, 'PermissionRequest.deny');
   WebViewInternal.setPermission(this.guestInstanceId, this.requestId, 'deny');
 };
 
diff --git a/headless/test/test_network_interceptor.cc b/headless/test/test_network_interceptor.cc
index 23799573..66a64f2e 100644
--- a/headless/test/test_network_interceptor.cc
+++ b/headless/test/test_network_interceptor.cc
@@ -35,11 +35,9 @@
     NotifyRedirect(std::move(url));
   };
 
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
 
   void ProceedWithResponse() override { DCHECK(false); }
   void SetPriority(net::RequestPriority priority,
@@ -126,9 +124,8 @@
 };
 
 void RedirectLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+    const std::vector<std::string>& removed_headers /* unused */,
+    const net::HttpRequestHeaders& modified_headers /* unused */,
     const base::Optional<GURL>& new_url) {
   response_ = interceptor_impl_->FindResponse(method_, url_.spec());
   CHECK(response_) << "No content for " << url_.spec();
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 408bd642..68bf54d 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -3501,6 +3501,7 @@
     # Linux
 
     builders { mixins: "linux"  name: "WebRTC Chromium Linux Builder" }
+    builders { mixins: "linux"  name: "WebRTC Chromium Linux Builder (RBE)" }
     builders { mixins: "linux"  name: "WebRTC Chromium Linux Tester" }
 
     # Mac
@@ -3558,7 +3559,9 @@
     # Linux
 
     builders { mixins: "linux"  name: "WebRTC Chromium FYI Linux Builder" }
+    builders { mixins: "linux"  name: "WebRTC Chromium FYI Linux Builder (RBE)" }
     builders { mixins: "linux"  name: "WebRTC Chromium FYI Linux Builder (dbg)" }
+    builders { mixins: "linux"  name: "WebRTC Chromium FYI Linux Builder (dbg) (RBE)" }
     builders { mixins: "linux"  name: "WebRTC Chromium FYI Linux Tester" }
 
     # Mac
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index 3b9b2fb..90b8ec3b 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -338,6 +338,7 @@
   triggers: "mac-views-rel"
   triggers: "WebRTC Chromium Android Builder"
   triggers: "WebRTC Chromium Linux Builder"
+  triggers: "WebRTC Chromium Linux Builder (RBE)"
   triggers: "WebRTC Chromium Mac Builder"
   triggers: "WebRTC Chromium Win Builder"
   triggers: "win-annotator-rel"
@@ -367,7 +368,9 @@
   triggers: "WebRTC Chromium FYI ios-simulator"
 
   triggers: "WebRTC Chromium FYI Linux Builder"
+  triggers: "WebRTC Chromium FYI Linux Builder (RBE)"
   triggers: "WebRTC Chromium FYI Linux Builder (dbg)"
+  triggers: "WebRTC Chromium FYI Linux Builder (dbg) (RBE)"
 
   triggers: "WebRTC Chromium FYI Mac Builder"
   triggers: "WebRTC Chromium FYI Mac Builder (dbg)"
@@ -1832,6 +1835,17 @@
 }
 
 job {
+  id: "WebRTC Chromium Linux Builder (RBE)"
+  acl_sets: "default"
+  acl_sets: "webrtc"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.webrtc"
+    builder: "WebRTC Chromium Linux Builder (RBE)"
+  }
+}
+
+job {
   id: "WebRTC Chromium Linux Tester"
   acl_sets: "triggered-by-parent-builders"
   acl_sets: "webrtc"
@@ -4977,6 +4991,17 @@
 }
 
 job {
+  id: "WebRTC Chromium FYI Linux Builder (RBE)"
+  acl_sets: "default"
+  acl_sets: "webrtc"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.webrtc.fyi"
+    builder: "WebRTC Chromium FYI Linux Builder (RBE)"
+  }
+}
+
+job {
   id: "WebRTC Chromium FYI Linux Tester"
   acl_sets: "triggered-by-parent-builders"
   acl_sets: "webrtc"
@@ -4999,6 +5024,17 @@
 }
 
 job {
+  id: "WebRTC Chromium FYI Linux Builder (dbg) (RBE)"
+  acl_sets: "default"
+  acl_sets: "webrtc"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.webrtc.fyi"
+    builder: "WebRTC Chromium FYI Linux Builder (dbg)"
+  }
+}
+
+job {
   id: "WebRTC Chromium FYI Mac Builder"
   acl_sets: "default"
   acl_sets: "webrtc"
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm b/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
index c0e02df..3b3f48d 100644
--- a/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
+++ b/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
@@ -12,7 +12,7 @@
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/metrics/tab_usage_recorder.h"
 #import "ios/chrome/browser/metrics/tab_usage_recorder_test_util.h"
-#import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
+#import "ios/chrome/browser/ui/settings/settings_table_view_controller.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
diff --git a/ios/chrome/browser/ntp/new_tab_page_tab_helper.mm b/ios/chrome/browser/ntp/new_tab_page_tab_helper.mm
index 8692a0c..5411c84 100644
--- a/ios/chrome/browser/ntp/new_tab_page_tab_helper.mm
+++ b/ios/chrome/browser/ntp/new_tab_page_tab_helper.mm
@@ -93,7 +93,7 @@
     return;
   }
 
-  SetActive(IsNTPURL(navigation_context->GetUrl()));
+  SetActive(IsNTPURL(web_state->GetLastCommittedURL()));
 }
 
 #pragma mark - Private
diff --git a/ios/chrome/browser/ntp/new_tab_page_tab_helper_unittest.mm b/ios/chrome/browser/ntp/new_tab_page_tab_helper_unittest.mm
index 541d653..039b920 100644
--- a/ios/chrome/browser/ntp/new_tab_page_tab_helper_unittest.mm
+++ b/ios/chrome/browser/ntp/new_tab_page_tab_helper_unittest.mm
@@ -136,12 +136,14 @@
   EXPECT_FALSE(tab_helper()->IsActive());
 
   GURL url(kChromeUINewTabURL);
+  test_web_state_.SetCurrentURL(url);
   web::FakeNavigationContext context;
   context.SetUrl(url);
   test_web_state_.OnNavigationFinished(&context);
   EXPECT_TRUE(tab_helper()->IsActive());
 
   GURL not_ntp_url(kTestURL);
+  test_web_state_.SetCurrentURL(not_ntp_url);
   context.SetUrl(not_ntp_url);
   test_web_state_.OnNavigationStarted(&context);
   EXPECT_FALSE(tab_helper()->IsActive());
@@ -149,10 +151,12 @@
   EXPECT_FALSE(tab_helper()->IsActive());
 
   context.SetUrl(url);
+  test_web_state_.SetCurrentURL(url);
   test_web_state_.OnNavigationFinished(&context);
   EXPECT_TRUE(tab_helper()->IsActive());
 
   context.SetUrl(not_ntp_url);
+  test_web_state_.SetCurrentURL(not_ntp_url);
   test_web_state_.OnNavigationStarted(&context);
   EXPECT_FALSE(tab_helper()->IsActive());
   test_web_state_.OnNavigationFinished(&context);
diff --git a/ios/chrome/browser/signin/signin_error_controller_factory.cc b/ios/chrome/browser/signin/signin_error_controller_factory.cc
index e8c61f2..ef48859 100644
--- a/ios/chrome/browser/signin/signin_error_controller_factory.cc
+++ b/ios/chrome/browser/signin/signin_error_controller_factory.cc
@@ -10,12 +10,9 @@
 #include "base/memory/singleton.h"
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_error_controller.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "ios/chrome/browser/signin/signin_manager_factory.h"
+#include "ios/chrome/browser/signin/identity_manager_factory.h"
 
 namespace ios {
 
@@ -35,8 +32,7 @@
     : BrowserStateKeyedServiceFactory(
           "SigninErrorController",
           BrowserStateDependencyManager::GetInstance()) {
-  DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
-  DependsOn(ios::SigninManagerFactory::GetInstance());
+  DependsOn(IdentityManagerFactory::GetInstance());
 }
 
 SigninErrorControllerFactory::~SigninErrorControllerFactory() {
@@ -49,9 +45,7 @@
       ChromeBrowserState::FromBrowserState(context);
   return std::make_unique<SigninErrorController>(
       SigninErrorController::AccountMode::ANY_ACCOUNT,
-      ProfileOAuth2TokenServiceFactory::GetForBrowserState(
-          chrome_browser_state),
-      ios::SigninManagerFactory::GetForBrowserState(chrome_browser_state));
+      IdentityManagerFactory::GetForBrowserState(chrome_browser_state));
 }
 
 }  // namespace ios
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 2ba7c50..557ca731 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -4732,17 +4732,8 @@
     // if needed. Not triggering it can create problem if the previous frame
     // wasn't the right one, for example in https://crbug.com/852106.
     [[self viewForTab:tab] layoutIfNeeded];
-    if (base::FeatureList::IsEnabled(
-            web::features::kBrowserContainerFullscreen)) {
-      newPage = [self viewForTab:tab];
-      newPage.userInteractionEnabled = NO;
-    } else {
-      UIImageView* pageScreenshot = [self pageOpenCloseAnimationView];
-      // TODO(crbug.com/917929): Refactor to remove usage of UpdateSnapshot().
-      pageScreenshot.image =
-          SnapshotTabHelper::FromWebState(tab.webState)->UpdateSnapshot();
-      newPage = pageScreenshot;
-    }
+    newPage = [self viewForTab:tab];
+    newPage.userInteractionEnabled = NO;
   }
 
   // Cleanup steps needed for both UI Refresh and stack-view style animations.
diff --git a/ios/chrome/browser/ui/history/history_ui_egtest.mm b/ios/chrome/browser/ui/history/history_ui_egtest.mm
index 65d7dd4c..2a514023 100644
--- a/ios/chrome/browser/ui/history/history_ui_egtest.mm
+++ b/ios/chrome/browser/ui/history/history_ui_egtest.mm
@@ -19,7 +19,7 @@
 #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
 #import "ios/chrome/browser/ui/history/history_ui_constants.h"
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h"
-#import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
+#import "ios/chrome/browser/ui/settings/settings_table_view_controller.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller_constants.h"
 #import "ios/chrome/browser/ui/util/transparent_link_button.h"
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn
index c01ddf6..a84b23f 100644
--- a/ios/chrome/browser/ui/settings/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -77,8 +77,6 @@
     "reauthentication_protocol.h",
     "search_engine_table_view_controller.h",
     "search_engine_table_view_controller.mm",
-    "settings_collection_view_controller.h",
-    "settings_collection_view_controller.mm",
     "settings_navigation_controller.h",
     "settings_navigation_controller.mm",
     "settings_root_collection_view_controller.h",
@@ -86,6 +84,8 @@
     "settings_root_table_view_controller.h",
     "settings_root_table_view_controller.mm",
     "settings_root_view_controlling.h",
+    "settings_table_view_controller.h",
+    "settings_table_view_controller.mm",
     "settings_utils.h",
     "settings_utils.mm",
     "sync_create_passphrase_table_view_controller.h",
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data_table_view_controller.mm b/ios/chrome/browser/ui/settings/clear_browsing_data_table_view_controller.mm
index 68004abb..99dbb06 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data_table_view_controller.mm
@@ -16,7 +16,7 @@
 #import "ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.h"
 #include "ios/chrome/browser/ui/settings/clear_browsing_data_local_commands.h"
 #import "ios/chrome/browser/ui/settings/clear_browsing_data_manager.h"
-#import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
+#import "ios/chrome/browser/ui/settings/settings_table_view_controller.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.h"
diff --git a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
index f15b783..19c413f 100644
--- a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
@@ -115,9 +115,6 @@
   ItemTypeImageDetailTextItem,
 };
 
-// Image fixed horizontal size.
-const CGFloat kHorizontalImageFixedSize = 40;
-
 // Credit Card icon size.
 const CGFloat kCardIssuerNetworkIconDimension = 25.0;
 
@@ -368,8 +365,6 @@
       toSectionWithIdentifier:SectionIdentifierAccountCell];
   [model addItem:[self accountItemCheckMark]
       toSectionWithIdentifier:SectionIdentifierAccountCell];
-  [model addItem:[self accountSignInItem]
-      toSectionWithIdentifier:SectionIdentifierAccountCell];
   [model addItem:[self coldStateSigninPromoItem]
       toSectionWithIdentifier:SectionIdentifierAccountCell];
   [model addItem:[self warmStateSigninPromoItem]
@@ -531,17 +526,6 @@
   return accountItemCheckMark;
 }
 
-- (CollectionViewItem*)accountSignInItem {
-  LegacyAccountSignInItem* accountSignInItem =
-      [[LegacyAccountSignInItem alloc] initWithType:ItemTypeAccountSignIn];
-  accountSignInItem.image =
-      CircularImageFromImage(ios::GetChromeBrowserProvider()
-                                 ->GetSigninResourcesProvider()
-                                 ->GetDefaultAvatar(),
-                             kHorizontalImageFixedSize);
-  return accountSignInItem;
-}
-
 - (CollectionViewItem*)coldStateSigninPromoItem {
   SigninPromoItem* signinPromoItem =
       [[SigninPromoItem alloc] initWithType:ItemTypeWarmStateSigninPromo];
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.h b/ios/chrome/browser/ui/settings/settings_navigation_controller.h
index c11dca01..46923da 100644
--- a/ios/chrome/browser/ui/settings/settings_navigation_controller.h
+++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.h
@@ -46,7 +46,7 @@
 // dismissed. Defaults to YES.
 @property(nonatomic, assign) BOOL shouldCommitSyncChangesOnDismissal;
 
-// Creates a new SettingsCollectionViewController and the chrome around it.
+// Creates a new SettingsTableViewController and the chrome around it.
 // |browserState| is used to personalize some settings aspects and should not be
 // nil nor Off-the-Record. |delegate| may be nil.
 + (SettingsNavigationController*)
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
index d26c27d..47bd7b2 100644
--- a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
@@ -19,8 +19,8 @@
 #import "ios/chrome/browser/ui/settings/google_services_settings_view_controller.h"
 #import "ios/chrome/browser/ui/settings/import_data_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/passwords_table_view_controller.h"
-#import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
 #import "ios/chrome/browser/ui/settings/settings_root_collection_view_controller.h"
+#import "ios/chrome/browser/ui/settings/settings_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/settings_utils.h"
 #import "ios/chrome/browser/ui/settings/sync_encryption_passphrase_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/sync_settings_collection_view_controller.h"
@@ -62,10 +62,9 @@
                                  delegate:
                                      (id<SettingsNavigationControllerDelegate>)
                                          delegate {
-  SettingsCollectionViewController* controller =
-      [[SettingsCollectionViewController alloc]
-          initWithBrowserState:browserState
-                    dispatcher:[delegate dispatcherForSettings]];
+  SettingsTableViewController* controller = [[SettingsTableViewController alloc]
+      initWithBrowserState:browserState
+                dispatcher:[delegate dispatcherForSettings]];
   SettingsNavigationController* nc = [[SettingsNavigationController alloc]
       initWithRootViewController:controller
                     browserState:browserState
diff --git a/ios/chrome/browser/ui/settings/settings_collection_view_controller.h b/ios/chrome/browser/ui/settings/settings_table_view_controller.h
similarity index 64%
rename from ios/chrome/browser/ui/settings/settings_collection_view_controller.h
rename to ios/chrome/browser/ui/settings/settings_table_view_controller.h
index 9c27492..2b156f4 100644
--- a/ios/chrome/browser/ui/settings/settings_collection_view_controller.h
+++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_SETTINGS_COLLECTION_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_SETTINGS_SETTINGS_COLLECTION_VIEW_CONTROLLER_H_
+#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_SETTINGS_TABLE_VIEW_CONTROLLER_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_SETTINGS_TABLE_VIEW_CONTROLLER_H_
 
 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
-#import "ios/chrome/browser/ui/settings/settings_root_collection_view_controller.h"
+#import "ios/chrome/browser/ui/settings/settings_root_table_view_controller.h"
 
 @protocol ApplicationCommands;
 @protocol SettingsMainPageCommands;
@@ -15,8 +15,8 @@
 class ChromeBrowserState;
 }  // namespace ios
 
-// The accessibility identifier of the settings collection view.
-extern NSString* const kSettingsCollectionViewId;
+// The accessibility identifier of the settings TableView.
+extern NSString* const kSettingsTableViewId;
 
 // The accessibility identifier for the settings' "Done" button.
 extern NSString* const kSettingsDoneButtonId;
@@ -33,27 +33,28 @@
 // The accessibility identifier of the Voice Search cell.
 extern NSString* const kSettingsVoiceSearchCellId;
 
-// This class is the collection view for the application settings.
-@interface SettingsCollectionViewController
-    : SettingsRootCollectionViewController<SettingsControllerProtocol>
+// This class is the TableView for the application settings.
+@interface SettingsTableViewController
+    : SettingsRootTableViewController <SettingsControllerProtocol>
 
 // Dispatcher for SettingsMainPageCommands. Defaults to self if not set.
 // TODO(crbug.com/738881): Unify this with the dispatcher passed into the init.
 @property(weak, nonatomic) id<SettingsMainPageCommands>
     settingsMainPageDispatcher;
 
-// Initializes a new SettingsCollectionViewController. |browserState| must not
+// Initializes a new SettingsTableViewController. |browserState| must not
 // be nil and must not be an off-the-record browser state.
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                           dispatcher:(id<ApplicationCommands>)dispatcher
     NS_DESIGNATED_INITIALIZER;
 
-- (instancetype)initWithLayout:(UICollectionViewLayout*)layout
-                         style:(CollectionViewControllerStyle)style
+- (instancetype)initWithTableViewStyle:(UITableViewStyle)style
+                           appBarStyle:
+                               (ChromeTableViewControllerStyle)appBarStyle
     NS_UNAVAILABLE;
 
 - (instancetype)init NS_UNAVAILABLE;
 
 @end
 
-#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_SETTINGS_COLLECTION_VIEW_CONTROLLER_H_
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_SETTINGS_TABLE_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
similarity index 80%
rename from ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
rename to ios/chrome/browser/ui/settings/settings_table_view_controller.mm
index 575197d8..5d4a3718d 100644
--- a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
+#import "ios/chrome/browser/ui/settings/settings_table_view_controller.h"
 
 #include <memory>
 
@@ -34,22 +34,20 @@
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
 #import "ios/chrome/browser/sync/sync_observer_bridge.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
-#import "ios/chrome/browser/ui/authentication/cells/signin_promo_item.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_consumer.h"
+#import "ios/chrome/browser/ui/authentication/cells/table_view_account_item.h"
+#import "ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h"
-#import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_account_item.h"
-#import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/chrome/browser/ui/commands/settings_main_page_commands.h"
 #import "ios/chrome/browser/ui/settings/about_chrome_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/accounts_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/autofill_credit_card_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/autofill_profile_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/bandwidth_management_table_view_controller.h"
-#import "ios/chrome/browser/ui/settings/cells/legacy/legacy_account_signin_item.h"
-#import "ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_detail_item.h"
-#import "ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_switch_item.h"
+#import "ios/chrome/browser/ui/settings/cells/account_sign_in_item.h"
+#import "ios/chrome/browser/ui/settings/cells/settings_detail_item.h"
+#import "ios/chrome/browser/ui/settings/cells/settings_switch_cell.h"
+#import "ios/chrome/browser/ui/settings/cells/settings_switch_item.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_text_item.h"
 #import "ios/chrome/browser/ui/settings/content_settings_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_coordinator.h"
@@ -63,6 +61,8 @@
 #import "ios/chrome/browser/ui/settings/voice_search_table_view_controller.h"
 #import "ios/chrome/browser/ui/signin_interaction/public/signin_presenter.h"
 #import "ios/chrome/browser/ui/signin_interaction/signin_interaction_coordinator.h"
+#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
+#import "ios/chrome/browser/ui/table_view/table_view_model.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #include "ios/chrome/browser/voice/speech_input_locale_config.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
@@ -78,14 +78,14 @@
 #error "This file requires ARC support."
 #endif
 
-NSString* const kSettingsCollectionViewId = @"kSettingsCollectionViewId";
+NSString* const kSettingsTableViewId = @"kSettingsTableViewId";
 NSString* const kSettingsDoneButtonId = @"kSettingsDoneButtonId";
 NSString* const kSettingsSignInCellId = @"kSettingsSignInCellId";
 NSString* const kSettingsAccountCellId = @"kSettingsAccountCellId";
 NSString* const kSettingsSearchEngineCellId = @"Search Engine";
 NSString* const kSettingsVoiceSearchCellId = @"Voice Search Settings";
 
-@interface SettingsCollectionViewController (NotificationBridgeDelegate)
+@interface SettingsTableViewController (NotificationBridgeDelegate)
 // Notifies this controller that the sign in state has changed.
 - (void)onSignInStateChanged;
 @end
@@ -150,7 +150,7 @@
 class IdentityObserverBridge : public identity::IdentityManager::Observer {
  public:
   IdentityObserverBridge(ios::ChromeBrowserState* browserState,
-                         SettingsCollectionViewController* owner);
+                         SettingsTableViewController* owner);
   ~IdentityObserverBridge() override {}
 
   // IdentityManager::Observer implementation:
@@ -159,13 +159,13 @@
       const AccountInfo& previous_primary_account_info) override;
 
  private:
-  __weak SettingsCollectionViewController* owner_;
+  __weak SettingsTableViewController* owner_;
   ScopedObserver<identity::IdentityManager, IdentityObserverBridge> observer_;
 };
 
 IdentityObserverBridge::IdentityObserverBridge(
     ios::ChromeBrowserState* browserState,
-    SettingsCollectionViewController* owner)
+    SettingsTableViewController* owner)
     : owner_(owner), observer_(this) {
   DCHECK(owner_);
   identity::IdentityManager* identity_manager =
@@ -187,9 +187,9 @@
 
 }  // namespace
 
-#pragma mark - SettingsCollectionViewController
+#pragma mark - SettingsTableViewController
 
-@interface SettingsCollectionViewController ()<
+@interface SettingsTableViewController () <
     BooleanObserver,
     ChromeIdentityServiceObserver,
     GoogleServicesSettingsCoordinatorDelegate,
@@ -211,9 +211,9 @@
   // PrefBackedBoolean for ArticlesForYou switch.
   PrefBackedBoolean* _articlesEnabled;
   // The item related to the switch for the show suggestions setting.
-  LegacySettingsSwitchItem* _showMemoryDebugToolsItem;
+  SettingsSwitchItem* _showMemoryDebugToolsItem;
   // The item related to the switch for the show suggestions setting.
-  LegacySettingsSwitchItem* _articlesForYouItem;
+  SettingsSwitchItem* _articlesForYouItem;
 
   // Mediator to configure the sign-in promo cell. Also used to received
   // identity update notifications.
@@ -238,11 +238,11 @@
   PrefChangeRegistrar _prefChangeRegistrar;
 
   // Updatable Items.
-  LegacySettingsDetailItem* _voiceSearchDetailItem;
-  LegacySettingsDetailItem* _defaultSearchEngineItem;
-  LegacySettingsDetailItem* _passwordsDetailItem;
-  LegacySettingsDetailItem* _autoFillProfileDetailItem;
-  LegacySettingsDetailItem* _autoFillCreditCardDetailItem;
+  SettingsDetailItem* _voiceSearchDetailItem;
+  SettingsDetailItem* _defaultSearchEngineItem;
+  SettingsDetailItem* _passwordsDetailItem;
+  SettingsDetailItem* _autoFillProfileDetailItem;
+  SettingsDetailItem* _autoFillCreditCardDetailItem;
 
   // YES if the user used at least once the sign-in promo view buttons.
   BOOL _signinStarted;
@@ -263,7 +263,7 @@
 
 @end
 
-@implementation SettingsCollectionViewController
+@implementation SettingsTableViewController
 @synthesize settingsMainPageDispatcher = _settingsMainPageDispatcher;
 @synthesize dispatcher = _dispatcher;
 @synthesize signinInteractionCoordinator = _signinInteractionCoordinator;
@@ -273,13 +273,11 @@
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                           dispatcher:(id<ApplicationCommands>)dispatcher {
   DCHECK(!browserState->IsOffTheRecord());
-  UICollectionViewLayout* layout = [[MDCCollectionViewFlowLayout alloc] init];
-  self = [super initWithLayout:layout
-                         style:CollectionViewControllerStyleDefault];
+  self = [super initWithTableViewStyle:UITableViewStyleGrouped
+                           appBarStyle:ChromeTableViewControllerStyleNoAppBar];
   if (self) {
     _browserState = browserState;
     self.title = l10n_util::GetNSStringWithFixup(IDS_IOS_SETTINGS_TITLE);
-    self.collectionViewAccessibilityIdentifier = kSettingsCollectionViewId;
     _notificationBridge.reset(new IdentityObserverBridge(_browserState, self));
     syncer::SyncService* syncService =
         ProfileSyncServiceFactory::GetForBrowserState(_browserState);
@@ -347,11 +345,12 @@
 - (void)viewDidLoad {
   [super viewDidLoad];
 
+  self.tableView.accessibilityIdentifier = kSettingsTableViewId;
+
   // Change the separator inset from the settings default because this
-  // collectionview shows leading icons.
-  const CGFloat kSettingsSeparatorLeadingInset = 56;
-  self.styler.separatorInset =
-      UIEdgeInsetsMake(0, kSettingsSeparatorLeadingInset, 0, 0);
+  // TableView shows leading icons.
+  self.tableView.separatorInset =
+      UIEdgeInsetsMake(0, kTableViewSeparatorInsetWithIcon, 0, 0);
 
   self.navigationItem.largeTitleDisplayMode =
       UINavigationItemLargeTitleDisplayModeAlways;
@@ -365,12 +364,12 @@
   [self updateSearchCell];
 }
 
-#pragma mark SettingsRootCollectionViewController
+#pragma mark SettingsRootTableViewController
 
 - (void)loadModel {
   [super loadModel];
 
-  CollectionViewModel* model = self.collectionViewModel;
+  TableViewModel<TableViewItem*>* model = self.tableViewModel;
 
   AuthenticationService* authService =
       AuthenticationServiceFactory::GetForBrowserState(_browserState);
@@ -471,12 +470,20 @@
 
 #pragma mark - Model Items
 
-- (CollectionViewItem*)signInTextItem {
+- (TableViewItem*)signInTextItem {
   if (_signinPromoViewMediator) {
-    SigninPromoItem* signinPromoItem =
-        [[SigninPromoItem alloc] initWithType:ItemTypeSigninPromo];
+    TableViewSigninPromoItem* signinPromoItem =
+        [[TableViewSigninPromoItem alloc] initWithType:ItemTypeSigninPromo];
+    if (unified_consent::IsUnifiedConsentFeatureEnabled()) {
+      signinPromoItem.text =
+          l10n_util::GetNSString(IDS_IOS_SIGNIN_PROMO_SETTINGS_WITH_UNITY);
+    } else {
+      signinPromoItem.text =
+          l10n_util::GetNSString(IDS_IOS_SIGNIN_PROMO_SETTINGS);
+    }
     signinPromoItem.configurator =
         [_signinPromoViewMediator createConfigurator];
+    signinPromoItem.delegate = _signinPromoViewMediator;
     [_signinPromoViewMediator signinPromoViewVisible];
     return signinPromoItem;
   }
@@ -487,18 +494,16 @@
         signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS);
     _hasRecordedSigninImpression = YES;
   }
-  LegacyAccountSignInItem* signInTextItem =
-      [[LegacyAccountSignInItem alloc] initWithType:ItemTypeSignInButton];
+  AccountSignInItem* signInTextItem =
+      [[AccountSignInItem alloc] initWithType:ItemTypeSignInButton];
   signInTextItem.accessibilityIdentifier = kSettingsSignInCellId;
-  UIImage* image = CircularImageFromImage(ios::GetChromeBrowserProvider()
-                                              ->GetSigninResourcesProvider()
-                                              ->GetDefaultAvatar(),
-                                          kAccountProfilePhotoDimension);
-  signInTextItem.image = image;
+  signInTextItem.detailText =
+      l10n_util::GetNSString(IDS_IOS_SIGN_IN_TO_CHROME_SETTING_SUBTITLE);
+
   return signInTextItem;
 }
 
-- (CollectionViewItem*)googleServicesCellItem {
+- (TableViewItem*)googleServicesCellItem {
   // TODO(crbug.com/805214): This branded icon image needs to come from
   // BrandedImageProvider.
   return [self detailItemWithType:ItemGoogleServices
@@ -508,18 +513,17 @@
                     iconImageName:kSyncAndGoogleServicesImageName];
 }
 
-- (CollectionViewItem*)accountCellItem {
-  CollectionViewAccountItem* identityAccountItem =
-      [[CollectionViewAccountItem alloc] initWithType:ItemTypeAccount];
-  identityAccountItem.cellStyle = CollectionViewCellStyle::kUIKit;
+- (TableViewItem*)accountCellItem {
+  TableViewAccountItem* identityAccountItem =
+      [[TableViewAccountItem alloc] initWithType:ItemTypeAccount];
   identityAccountItem.accessoryType =
-      MDCCollectionViewCellAccessoryDisclosureIndicator;
+      UITableViewCellAccessoryDisclosureIndicator;
   identityAccountItem.accessibilityIdentifier = kSettingsAccountCellId;
   [self updateIdentityAccountItem:identityAccountItem];
   return identityAccountItem;
 }
 
-- (CollectionViewItem*)searchEngineDetailItem {
+- (TableViewItem*)searchEngineDetailItem {
   NSString* defaultSearchEngineName =
       base::SysUTF16ToNSString(GetDefaultSearchEngineName(
           ios::TemplateURLServiceFactory::GetForBrowserState(_browserState)));
@@ -535,7 +539,7 @@
   return _defaultSearchEngineItem;
 }
 
-- (CollectionViewItem*)passwordsDetailItem {
+- (TableViewItem*)passwordsDetailItem {
   BOOL passwordsEnabled = _browserState->GetPrefs()->GetBoolean(
       password_manager::prefs::kCredentialsEnableService);
   NSString* passwordsDetail = passwordsEnabled
@@ -550,7 +554,7 @@
   return _passwordsDetailItem;
 }
 
-- (CollectionViewItem*)AutoFillCreditCardDetailItem {
+- (TableViewItem*)AutoFillCreditCardDetailItem {
   BOOL autofillCreditCardEnabled =
       autofill::prefs::IsCreditCardAutofillEnabled(_browserState->GetPrefs());
   NSString* detailText = autofillCreditCardEnabled
@@ -565,7 +569,7 @@
   return _autoFillCreditCardDetailItem;
 }
 
-- (CollectionViewItem*)autoFillProfileDetailItem {
+- (TableViewItem*)autoFillProfileDetailItem {
   BOOL autofillProfileEnabled =
       autofill::prefs::IsProfileAutofillEnabled(_browserState->GetPrefs());
   NSString* detailText = autofillProfileEnabled
@@ -581,7 +585,7 @@
   return _autoFillProfileDetailItem;
 }
 
-- (CollectionViewItem*)voiceSearchDetailItem {
+- (TableViewItem*)voiceSearchDetailItem {
   voice::SpeechInputLocaleConfig* localeConfig =
       voice::SpeechInputLocaleConfig::GetInstance();
   voice::SpeechInputLocale locale =
@@ -599,7 +603,7 @@
   return _voiceSearchDetailItem;
 }
 
-- (CollectionViewItem*)privacyDetailItem {
+- (TableViewItem*)privacyDetailItem {
   return
       [self detailItemWithType:ItemTypePrivacy
                           text:l10n_util::GetNSString(
@@ -608,7 +612,7 @@
                  iconImageName:kSettingsPrivacyImageName];
 }
 
-- (CollectionViewItem*)contentSettingsDetailItem {
+- (TableViewItem*)contentSettingsDetailItem {
   return [self
       detailItemWithType:ItemTypeContentSettings
                     text:l10n_util::GetNSString(IDS_IOS_CONTENT_SETTINGS_TITLE)
@@ -616,7 +620,7 @@
            iconImageName:kSettingsContentSettingsImageName];
 }
 
-- (CollectionViewItem*)bandwidthManagementDetailItem {
+- (TableViewItem*)bandwidthManagementDetailItem {
   return [self detailItemWithType:ItemTypeBandwidth
                              text:l10n_util::GetNSString(
                                       IDS_IOS_BANDWIDTH_MANAGEMENT_SETTINGS)
@@ -624,15 +628,15 @@
                     iconImageName:kSettingsBandwidthImageName];
 }
 
-- (CollectionViewItem*)aboutChromeDetailItem {
+- (TableViewItem*)aboutChromeDetailItem {
   return [self detailItemWithType:ItemTypeAboutChrome
                              text:l10n_util::GetNSString(IDS_IOS_PRODUCT_NAME)
                        detailText:nil
                     iconImageName:kSettingsAboutChromeImageName];
 }
 
-- (LegacySettingsSwitchItem*)showMemoryDebugSwitchItem {
-  LegacySettingsSwitchItem* showMemoryDebugSwitchItem =
+- (SettingsSwitchItem*)showMemoryDebugSwitchItem {
+  SettingsSwitchItem* showMemoryDebugSwitchItem =
       [self switchItemWithType:ItemTypeMemoryDebugging
                          title:@"Show memory debug tools"
                  iconImageName:kSettingsDebugImageName
@@ -642,8 +646,8 @@
   return showMemoryDebugSwitchItem;
 }
 
-- (LegacySettingsSwitchItem*)articlesForYouSwitchItem {
-  LegacySettingsSwitchItem* articlesForYouSwitchItem =
+- (SettingsSwitchItem*)articlesForYouSwitchItem {
+  SettingsSwitchItem* articlesForYouSwitchItem =
       [self switchItemWithType:ItemTypeArticlesForYou
                          title:l10n_util::GetNSString(
                                    IDS_IOS_CONTENT_SUGGESTIONS_SETTING_TITLE)
@@ -655,21 +659,21 @@
 }
 #if CHROMIUM_BUILD && !defined(NDEBUG)
 
-- (LegacySettingsSwitchItem*)viewSourceSwitchItem {
+- (SettingsSwitchItem*)viewSourceSwitchItem {
   return [self switchItemWithType:ItemTypeViewSource
                             title:@"View source menu"
                     iconImageName:kSettingsDebugImageName
                   withDefaultsKey:kDevViewSourceKey];
 }
 
-- (LegacySettingsDetailItem*)collectionViewCatalogDetailItem {
+- (SettingsDetailItem*)collectionViewCatalogDetailItem {
   return [self detailItemWithType:ItemTypeCollectionCellCatalog
                              text:@"Collection Cell Catalog"
                        detailText:nil
                     iconImageName:kSettingsDebugImageName];
 }
 
-- (LegacySettingsDetailItem*)tableViewCatalogDetailItem {
+- (SettingsDetailItem*)tableViewCatalogDetailItem {
   return [self detailItemWithType:ItemTypeTableCellCatalog
                              text:@"TableView Cell Catalog"
                        detailText:nil
@@ -690,27 +694,27 @@
 
 #pragma mark Item Constructors
 
-- (LegacySettingsDetailItem*)detailItemWithType:(NSInteger)type
-                                           text:(NSString*)text
-                                     detailText:(NSString*)detailText
-                                  iconImageName:(NSString*)iconImageName {
-  LegacySettingsDetailItem* detailItem =
-      [[LegacySettingsDetailItem alloc] initWithType:type];
+- (SettingsDetailItem*)detailItemWithType:(NSInteger)type
+                                     text:(NSString*)text
+                               detailText:(NSString*)detailText
+                            iconImageName:(NSString*)iconImageName {
+  SettingsDetailItem* detailItem =
+      [[SettingsDetailItem alloc] initWithType:type];
   detailItem.text = text;
   detailItem.detailText = detailText;
-  detailItem.accessoryType = MDCCollectionViewCellAccessoryDisclosureIndicator;
+  detailItem.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
   detailItem.iconImageName = iconImageName;
   detailItem.accessibilityTraits |= UIAccessibilityTraitButton;
 
   return detailItem;
 }
 
-- (LegacySettingsSwitchItem*)switchItemWithType:(NSInteger)type
-                                          title:(NSString*)title
-                                  iconImageName:(NSString*)iconImageName
-                                withDefaultsKey:(NSString*)key {
-  LegacySettingsSwitchItem* switchItem =
-      [[LegacySettingsSwitchItem alloc] initWithType:type];
+- (SettingsSwitchItem*)switchItemWithType:(NSInteger)type
+                                    title:(NSString*)title
+                            iconImageName:(NSString*)iconImageName
+                          withDefaultsKey:(NSString*)key {
+  SettingsSwitchItem* switchItem =
+      [[SettingsSwitchItem alloc] initWithType:type];
   switchItem.text = title;
   switchItem.iconImageName = iconImageName;
   if (key) {
@@ -721,18 +725,17 @@
   return switchItem;
 }
 
-#pragma mark - UICollectionViewDataSource
+#pragma mark - UITableViewDataSource
 
-- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
-                 cellForItemAtIndexPath:(NSIndexPath*)indexPath {
-  UICollectionViewCell* cell =
-      [super collectionView:collectionView cellForItemAtIndexPath:indexPath];
-  NSInteger itemType =
-      [self.collectionViewModel itemTypeForIndexPath:indexPath];
+- (UITableViewCell*)tableView:(UITableView*)tableView
+        cellForRowAtIndexPath:(NSIndexPath*)indexPath {
+  UITableViewCell* cell = [super tableView:tableView
+                     cellForRowAtIndexPath:indexPath];
+  NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath];
 
-  if ([cell isKindOfClass:[LegacySettingsDetailCell class]]) {
-    LegacySettingsDetailCell* detailCell =
-        base::mac::ObjCCastStrict<LegacySettingsDetailCell>(cell);
+  if ([cell isKindOfClass:[SettingsDetailCell class]]) {
+    SettingsDetailCell* detailCell =
+        base::mac::ObjCCastStrict<SettingsDetailCell>(cell);
     if (itemType == ItemTypePasswords) {
       scoped_refptr<password_manager::PasswordStore> passwordStore =
           IOSChromePasswordStoreFactory::GetForBrowserState(
@@ -744,45 +747,37 @@
         LOG(ERROR) << "Save passwords cell was disabled as the password store"
                       " cannot be created.";
         [detailCell setUserInteractionEnabled:NO];
-        detailCell.textLabel.textColor = [[MDCPalette greyPalette] tint500];
-        detailCell.detailTextLabel.textColor =
-            [[MDCPalette greyPalette] tint400];
+        detailCell.textLabel.textColor =
+            UIColorFromRGB(kTableViewSecondaryLabelLightGrayTextColor);
         return cell;
       }
     }
 
     [detailCell setUserInteractionEnabled:YES];
-    detailCell.textLabel.textColor = [[MDCPalette greyPalette] tint900];
-    detailCell.detailTextLabel.textColor = [[MDCPalette greyPalette] tint500];
+    detailCell.textLabel.textColor = UIColor.blackColor;
   }
 
   switch (itemType) {
     case ItemTypeMemoryDebugging: {
-      LegacySettingsSwitchCell* switchCell =
-          base::mac::ObjCCastStrict<LegacySettingsSwitchCell>(cell);
+      SettingsSwitchCell* switchCell =
+          base::mac::ObjCCastStrict<SettingsSwitchCell>(cell);
       [switchCell.switchView addTarget:self
                                 action:@selector(memorySwitchToggled:)
                       forControlEvents:UIControlEventValueChanged];
       break;
     }
     case ItemTypeArticlesForYou: {
-      LegacySettingsSwitchCell* switchCell =
-          base::mac::ObjCCastStrict<LegacySettingsSwitchCell>(cell);
+      SettingsSwitchCell* switchCell =
+          base::mac::ObjCCastStrict<SettingsSwitchCell>(cell);
       [switchCell.switchView addTarget:self
                                 action:@selector(articlesForYouSwitchToggled:)
                       forControlEvents:UIControlEventValueChanged];
       break;
     }
-    case ItemTypeSigninPromo: {
-      SigninPromoCell* signinPromoCell =
-          base::mac::ObjCCast<SigninPromoCell>(cell);
-      signinPromoCell.signinPromoView.delegate = _signinPromoViewMediator;
-      break;
-    }
     case ItemTypeViewSource: {
 #if CHROMIUM_BUILD && !defined(NDEBUG)
-      LegacySettingsSwitchCell* switchCell =
-          base::mac::ObjCCastStrict<LegacySettingsSwitchCell>(cell);
+      SettingsSwitchCell* switchCell =
+          base::mac::ObjCCastStrict<SettingsSwitchCell>(cell);
       [switchCell.switchView addTarget:self
                                 action:@selector(viewSourceSwitchToggled:)
                       forControlEvents:UIControlEventValueChanged];
@@ -798,21 +793,18 @@
   return cell;
 }
 
-#pragma mark UICollectionViewDelegate
+#pragma mark UITableViewDelegate
 
-- (void)collectionView:(UICollectionView*)collectionView
-    didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
-  [super collectionView:collectionView didSelectItemAtIndexPath:indexPath];
-
-  id object = [self.collectionViewModel itemAtIndexPath:indexPath];
+- (void)tableView:(UITableView*)tableView
+    didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
+  id object = [self.tableViewModel itemAtIndexPath:indexPath];
   if ([object respondsToSelector:@selector(isEnabled)] &&
       ![object performSelector:@selector(isEnabled)]) {
     // Don't perform any action if the cell isn't enabled.
     return;
   }
 
-  NSInteger itemType =
-      [self.collectionViewModel itemTypeForIndexPath:indexPath];
+  NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath];
 
   UIViewController<SettingsRootViewControlling>* controller;
 
@@ -892,53 +884,16 @@
   }
 }
 
-#pragma mark MDCCollectionViewStylingDelegate
-
-- (CGFloat)collectionView:(UICollectionView*)collectionView
-    cellHeightAtIndexPath:(NSIndexPath*)indexPath {
-  CollectionViewItem* item =
-      [self.collectionViewModel itemAtIndexPath:indexPath];
-
-  if (item.type == ItemTypeSigninPromo) {
-    return [MDCCollectionViewCell
-        cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds)
-                           forItem:item];
-  }
-
-  if (item.type == ItemTypeAccount) {
-    return MDCCellDefaultTwoLineHeight;
-  }
-
-  if (item.type == ItemTypeSignInButton) {
-    return MDCCellDefaultThreeLineHeight;
-  }
-
-  return MDCCellDefaultOneLineHeight;
-}
-
-- (BOOL)collectionView:(UICollectionView*)collectionView
-    hidesInkViewAtIndexPath:(NSIndexPath*)indexPath {
-  NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath];
-  switch (type) {
-    case ItemTypeMemoryDebugging:
-    case ItemTypeSigninPromo:
-    case ItemTypeViewSource:
-      return YES;
-    default:
-      return NO;
-  }
-}
-
 #pragma mark Switch Actions
 
 - (void)memorySwitchToggled:(UISwitch*)sender {
   NSIndexPath* switchPath =
-      [self.collectionViewModel indexPathForItemType:ItemTypeMemoryDebugging
-                                   sectionIdentifier:SectionIdentifierDebug];
+      [self.tableViewModel indexPathForItemType:ItemTypeMemoryDebugging
+                              sectionIdentifier:SectionIdentifierDebug];
 
-  LegacySettingsSwitchItem* switchItem =
-      base::mac::ObjCCastStrict<LegacySettingsSwitchItem>(
-          [self.collectionViewModel itemAtIndexPath:switchPath]);
+  SettingsSwitchItem* switchItem =
+      base::mac::ObjCCastStrict<SettingsSwitchItem>(
+          [self.tableViewModel itemAtIndexPath:switchPath]);
 
   BOOL newSwitchValue = sender.isOn;
   switchItem.on = newSwitchValue;
@@ -947,12 +902,12 @@
 
 - (void)articlesForYouSwitchToggled:(UISwitch*)sender {
   NSIndexPath* switchPath =
-      [self.collectionViewModel indexPathForItemType:ItemTypeArticlesForYou
-                                   sectionIdentifier:SectionIdentifierAdvanced];
+      [self.tableViewModel indexPathForItemType:ItemTypeArticlesForYou
+                              sectionIdentifier:SectionIdentifierAdvanced];
 
-  LegacySettingsSwitchItem* switchItem =
-      base::mac::ObjCCastStrict<LegacySettingsSwitchItem>(
-          [self.collectionViewModel itemAtIndexPath:switchPath]);
+  SettingsSwitchItem* switchItem =
+      base::mac::ObjCCastStrict<SettingsSwitchItem>(
+          [self.tableViewModel itemAtIndexPath:switchPath]);
 
   BOOL newSwitchValue = sender.isOn;
   switchItem.on = newSwitchValue;
@@ -962,12 +917,12 @@
 #if CHROMIUM_BUILD && !defined(NDEBUG)
 - (void)viewSourceSwitchToggled:(UISwitch*)sender {
   NSIndexPath* switchPath =
-      [self.collectionViewModel indexPathForItemType:ItemTypeViewSource
-                                   sectionIdentifier:SectionIdentifierDebug];
+      [self.tableViewModel indexPathForItemType:ItemTypeViewSource
+                              sectionIdentifier:SectionIdentifierDebug];
 
-  LegacySettingsSwitchItem* switchItem =
-      base::mac::ObjCCastStrict<LegacySettingsSwitchItem>(
-          [self.collectionViewModel itemAtIndexPath:switchPath]);
+  SettingsSwitchItem* switchItem =
+      base::mac::ObjCCastStrict<SettingsSwitchItem>(
+          [self.tableViewModel itemAtIndexPath:switchPath]);
 
   BOOL newSwitchValue = sender.isOn;
   switchItem.on = newSwitchValue;
@@ -1012,8 +967,7 @@
 }
 
 // Updates the identity cell.
-- (void)updateIdentityAccountItem:
-    (CollectionViewAccountItem*)identityAccountItem {
+- (void)updateIdentityAccountItem:(TableViewAccountItem*)identityAccountItem {
   AuthenticationService* authService =
       AuthenticationServiceFactory::GetForBrowserState(_browserState);
   _identity = authService->GetAuthenticatedIdentity();
@@ -1050,16 +1004,16 @@
 }
 
 - (void)reloadAccountCell {
-  if (![self.collectionViewModel hasItemForItemType:ItemTypeAccount
-                                  sectionIdentifier:SectionIdentifierAccount]) {
+  if (![self.tableViewModel hasItemForItemType:ItemTypeAccount
+                             sectionIdentifier:SectionIdentifierAccount]) {
     return;
   }
   NSIndexPath* accountCellIndexPath =
-      [self.collectionViewModel indexPathForItemType:ItemTypeAccount
-                                   sectionIdentifier:SectionIdentifierAccount];
-  CollectionViewAccountItem* identityAccountItem =
-      base::mac::ObjCCast<CollectionViewAccountItem>(
-          [self.collectionViewModel itemAtIndexPath:accountCellIndexPath]);
+      [self.tableViewModel indexPathForItemType:ItemTypeAccount
+                              sectionIdentifier:SectionIdentifierAccount];
+  TableViewAccountItem* identityAccountItem =
+      base::mac::ObjCCast<TableViewAccountItem>(
+          [self.tableViewModel itemAtIndexPath:accountCellIndexPath]);
   if (identityAccountItem) {
     [self updateIdentityAccountItem:identityAccountItem];
     [self reconfigureCellsForItems:@[ identityAccountItem ]];
@@ -1084,7 +1038,7 @@
                   dispatcher:self.dispatcher];
   }
 
-  __weak SettingsCollectionViewController* weakSelf = self;
+  __weak SettingsTableViewController* weakSelf = self;
   [self.signinInteractionCoordinator
             signInWithIdentity:identity
                    accessPoint:signin_metrics::AccessPoint::
@@ -1116,13 +1070,13 @@
 #pragma mark NotificationBridgeDelegate
 
 - (void)onSignInStateChanged {
-  // While the sign-in interaction coordinator is presenting UI, the collection
-  // view should not be updated. Otherwise, it would lead to have an UI glitch
-  // either while the sign in UI is appearing or while it is disappearing. The
-  // collection view will be reloaded once the animation is finished.
-  // See: -[SettingsCollectionViewController didFinishSignin:].
+  // While the sign-in interaction coordinator is presenting UI, the TableView
+  // should not be updated. Otherwise, it would lead to have an UI glitch either
+  // while the sign in UI is appearing or while it is disappearing. The
+  // TableView will be reloaded once the animation is finished.
+  // See: -[SettingsTableViewController didFinishSignin:].
   if (!self.signinInteractionCoordinator.isActive) {
-    // Sign in state changes are rare. Just reload the entire collection when
+    // Sign in state changes are rare. Just reload the entire table when
     // this happens.
     [self reloadData];
   }
@@ -1260,21 +1214,21 @@
             (SigninPromoViewConfigurator*)configurator
                              identityChanged:(BOOL)identityChanged {
   DCHECK(!self.signinInteractionCoordinator.isActive);
-  if (![self.collectionViewModel hasItemForItemType:ItemTypeSigninPromo
-                                  sectionIdentifier:SectionIdentifierSignIn]) {
+  if (![self.tableViewModel hasItemForItemType:ItemTypeSigninPromo
+                             sectionIdentifier:SectionIdentifierSignIn]) {
     return;
   }
   NSIndexPath* signinPromoCellIndexPath =
-      [self.collectionViewModel indexPathForItemType:ItemTypeSigninPromo
-                                   sectionIdentifier:SectionIdentifierSignIn];
+      [self.tableViewModel indexPathForItemType:ItemTypeSigninPromo
+                              sectionIdentifier:SectionIdentifierSignIn];
   DCHECK(signinPromoCellIndexPath.item != NSNotFound);
-  SigninPromoItem* signinPromoItem = base::mac::ObjCCast<SigninPromoItem>(
-      [self.collectionViewModel itemAtIndexPath:signinPromoCellIndexPath]);
+  TableViewSigninPromoItem* signinPromoItem =
+      base::mac::ObjCCast<TableViewSigninPromoItem>(
+          [self.tableViewModel itemAtIndexPath:signinPromoCellIndexPath]);
   if (signinPromoItem) {
     signinPromoItem.configurator = configurator;
+    signinPromoItem.delegate = _signinPromoViewMediator;
     [self reconfigureCellsForItems:@[ signinPromoItem ]];
-    if (identityChanged)
-      [self.collectionViewLayout invalidateLayout];
   }
 }
 
diff --git a/ios/chrome/browser/ui/settings/signin_settings_egtest.mm b/ios/chrome/browser/ui/settings/signin_settings_egtest.mm
index d1c3961..dd08ae9 100644
--- a/ios/chrome/browser/ui/settings/signin_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/signin_settings_egtest.mm
@@ -10,7 +10,7 @@
 #include "ios/chrome/browser/pref_names.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h"
 #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
-#import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
+#import "ios/chrome/browser/ui/settings/settings_table_view_controller.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
diff --git a/ios/chrome/browser/ui/settings/sync_utils/sync_fake_server_egtest.mm b/ios/chrome/browser/ui/settings/sync_utils/sync_fake_server_egtest.mm
index 02fbed8..757fb4c3 100644
--- a/ios/chrome/browser/ui/settings/sync_utils/sync_fake_server_egtest.mm
+++ b/ios/chrome/browser/ui/settings/sync_utils/sync_fake_server_egtest.mm
@@ -20,7 +20,7 @@
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h"
 #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
-#import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
+#import "ios/chrome/browser/ui/settings/settings_table_view_controller.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/app/bookmarks_test_util.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
diff --git a/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
index 3cdadcf..1609c1e 100644
--- a/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
@@ -27,6 +27,9 @@
 #import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 #import "ios/chrome/browser/ui/table_view/table_view_model.h"
+#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
+#import "ios/public/provider/chrome/browser/signin/signin_resources_provider.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm b/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm
index c52889e0..a867b99 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey_ui.mm
@@ -11,7 +11,7 @@
 #import "ios/chrome/browser/ui/settings/accounts_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/clear_browsing_data_ui_constants.h"
 #import "ios/chrome/browser/ui/settings/privacy_table_view_controller.h"
-#import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
+#import "ios/chrome/browser/ui/settings/settings_table_view_controller.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.mm b/ios/chrome/test/earl_grey/chrome_matchers.mm
index 015e533..a391b290 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers.mm
+++ b/ios/chrome/test/earl_grey/chrome_matchers.mm
@@ -31,7 +31,7 @@
 #import "ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.h"
 #import "ios/chrome/browser/ui/settings/clear_browsing_data_ui_constants.h"
 #import "ios/chrome/browser/ui/settings/import_data_table_view_controller.h"
-#import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
+#import "ios/chrome/browser/ui/settings/settings_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/sync_settings_collection_view_controller.h"
 #import "ios/chrome/browser/ui/static_content/static_html_view_controller.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
@@ -484,7 +484,7 @@
 }
 
 id<GREYMatcher> SettingsCollectionView() {
-  return grey_accessibilityID(kSettingsCollectionViewId);
+  return grey_accessibilityID(kSettingsTableViewId);
 }
 
 id<GREYMatcher> ClearBrowsingHistoryButton() {
diff --git a/ios/web/navigation/wk_navigation_util.mm b/ios/web/navigation/wk_navigation_util.mm
index c9944c6..b684a59f 100644
--- a/ios/web/navigation/wk_navigation_util.mm
+++ b/ios/web/navigation/wk_navigation_util.mm
@@ -78,6 +78,7 @@
 
 bool URLNeedsUserAgentType(const GURL& url) {
   return !web::GetWebClient()->IsAppSpecificURL(url) &&
+         !(url.SchemeIs(url::kFileScheme) && !IsRestoreSessionUrl(url)) &&
          !(url.SchemeIs(url::kAboutScheme) && !IsPlaceholderUrl(url));
 }
 
diff --git a/ios/web/navigation/wk_navigation_util_unittest.mm b/ios/web/navigation/wk_navigation_util_unittest.mm
index 2e71c6a..20dd44b 100644
--- a/ios/web/navigation/wk_navigation_util_unittest.mm
+++ b/ios/web/navigation/wk_navigation_util_unittest.mm
@@ -303,6 +303,9 @@
   // Not a placeholder or normal URL.
   EXPECT_TRUE(URLNeedsUserAgentType(GURL("about:blank?for=")));
   EXPECT_TRUE(URLNeedsUserAgentType(GURL("http://www.0.com")));
+
+  // file:// URL.
+  EXPECT_FALSE(URLNeedsUserAgentType(GURL("file://foo.pdf")));
 }
 
 }  // namespace wk_navigation_util
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 6b2e1193..1a3126951 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -31,6 +31,7 @@
 #import "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/context_menu_params.h"
 #import "ios/web/public/web_state/ui/crw_content_view.h"
+#import "ios/web/public/web_state/ui/crw_native_content.h"
 #import "ios/web/public/web_state/web_state_delegate.h"
 #include "ios/web/public/web_state/web_state_interface_provider.h"
 #include "ios/web/public/web_state/web_state_observer.h"
@@ -683,26 +684,37 @@
 }
 
 GURL WebStateImpl::GetCurrentURL(URLVerificationTrustLevel* trust_level) const {
-  GURL URL = [web_controller_ currentURLWithTrustLevel:trust_level];
+  GURL result = [web_controller_ currentURLWithTrustLevel:trust_level];
 
-  GURL lastCommittedUrl = GetLastCommittedURL();
+  web::NavigationItem* item = navigation_manager_->GetLastCommittedItem();
+  GURL lastCommittedURL;
+  if (item) {
+    if ([web_controller_.nativeController
+            respondsToSelector:@selector(virtualURL)]) {
+      // For native content |currentURLWithTrustLevel:| returns virtual URL if
+      // one is available.
+      lastCommittedURL = item->GetVirtualURL();
+    } else {
+      // Otherwise document URL is returned.
+      lastCommittedURL = item->GetURL();
+    }
+  }
+
   bool equalOrigins;
-  if (URL.SchemeIs(url::kAboutScheme) &&
-      web::GetWebClient()->IsAppSpecificURL(lastCommittedUrl)) {
+  if (result.SchemeIs(url::kAboutScheme) &&
+      web::GetWebClient()->IsAppSpecificURL(GetLastCommittedURL())) {
     // This special case is added for any app specific URLs that have been
     // rewritten to about:// URLs.  In this case, an about scheme does not have
     // an origin to compare, only a path.
-    web::NavigationItem* item = navigation_manager_->GetLastCommittedItem();
-    GURL lastCommittedUrl = item ? item->GetURL() : GURL::EmptyGURL();
-    equalOrigins = URL.path() == lastCommittedUrl.path();
+    equalOrigins = result.path() == lastCommittedURL.path();
   } else {
-    equalOrigins = URL.GetOrigin() == lastCommittedUrl.GetOrigin();
+    equalOrigins = result.GetOrigin() == lastCommittedURL.GetOrigin();
   }
-  DCHECK(equalOrigins) << "Origin mismatch. URL: " << URL.spec()
-                       << " Last committed: " << lastCommittedUrl.spec();
+  DCHECK(equalOrigins) << "Origin mismatch. URL: " << result.spec()
+                       << " Last committed: " << lastCommittedURL.spec();
   UMA_HISTOGRAM_BOOLEAN("Web.CurrentOriginEqualsLastCommittedOrigin",
                         equalOrigins);
-  return URL;
+  return result;
 }
 
 void WebStateImpl::AddScriptCommandCallback(
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index dd1108f7..c2a72fe4 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -429,6 +429,7 @@
     "//components/sync:test_support_driver",
     "//ios/web/public/test",
     "//ios/web/public/test/fakes",
+    "//services/identity/public/cpp:test_support",
     "//testing/gtest",
     "//third_party/ocmock",
   ]
diff --git a/ios/web_view/internal/signin/web_view_signin_error_controller_factory.mm b/ios/web_view/internal/signin/web_view_signin_error_controller_factory.mm
index cd47e8e..1f3b7e8 100644
--- a/ios/web_view/internal/signin/web_view_signin_error_controller_factory.mm
+++ b/ios/web_view/internal/signin/web_view_signin_error_controller_factory.mm
@@ -9,11 +9,8 @@
 #include "base/memory/singleton.h"
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_error_controller.h"
-#include "components/signin/core/browser/signin_manager.h"
-#include "ios/web_view/internal/signin/web_view_oauth2_token_service_factory.h"
-#include "ios/web_view/internal/signin/web_view_signin_manager_factory.h"
+#include "ios/web_view/internal/signin/web_view_identity_manager_factory.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -39,8 +36,7 @@
     : BrowserStateKeyedServiceFactory(
           "SigninErrorController",
           BrowserStateDependencyManager::GetInstance()) {
-  DependsOn(WebViewOAuth2TokenServiceFactory::GetInstance());
-  DependsOn(WebViewSigninManagerFactory::GetInstance());
+  DependsOn(WebViewIdentityManagerFactory::GetInstance());
 }
 
 std::unique_ptr<KeyedService>
@@ -50,8 +46,7 @@
       WebViewBrowserState::FromBrowserState(context);
   return std::make_unique<SigninErrorController>(
       SigninErrorController::AccountMode::ANY_ACCOUNT,
-      WebViewOAuth2TokenServiceFactory::GetForBrowserState(browser_state),
-      WebViewSigninManagerFactory::GetForBrowserState(browser_state));
+      WebViewIdentityManagerFactory::GetForBrowserState(browser_state));
 }
 
 }  // namespace ios_web_view
diff --git a/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm b/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
index 98da11a5..40168f0 100644
--- a/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
+++ b/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
@@ -30,6 +30,7 @@
 #import "ios/web_view/public/cwv_identity.h"
 #import "ios/web_view/public/cwv_sync_controller_data_source.h"
 #import "ios/web_view/public/cwv_sync_controller_delegate.h"
+#include "services/identity/public/cpp/identity_test_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
@@ -65,10 +66,13 @@
                         &token_service_,
                         &account_tracker_service_,
                         &gaia_cookie_manager_service_),
+        identity_test_env_(&account_tracker_service_,
+                           &token_service_,
+                           &signin_manager_,
+                           &gaia_cookie_manager_service_),
         signin_error_controller_(
             SigninErrorController::AccountMode::ANY_ACCOUNT,
-            &token_service_,
-            &signin_manager_) {
+            identity_test_env_.identity_manager()) {
     web_state_.SetBrowserState(&browser_state_);
 
     browser_sync::ProfileSyncService::InitParams init_params;
@@ -122,6 +126,7 @@
   FakeProfileOAuth2TokenService token_service_;
   FakeGaiaCookieManagerService gaia_cookie_manager_service_;
   FakeSigninManager signin_manager_;
+  identity::IdentityTestEnvironment identity_test_env_;
   SigninErrorController signin_error_controller_;
   CWVSyncController* sync_controller_;
   syncer::SyncServiceObserver* sync_service_observer_;
diff --git a/media/audio/audio_features.cc b/media/audio/audio_features.cc
index 5e8bb39..ae38fa4 100644
--- a/media/audio/audio_features.cc
+++ b/media/audio/audio_features.cc
@@ -9,7 +9,7 @@
 // If enabled, base::DumpWithoutCrashing is called whenever an audio service
 // hang is detected.
 const base::Feature kDumpOnAudioServiceHang{"DumpOnAudioServiceHang",
-                                            base::FEATURE_ENABLED_BY_DEFAULT};
+                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
 #if defined(OS_CHROMEOS)
 // Allows experimentally enables mediaDevices.enumerateDevices() on ChromeOS.
diff --git a/media/audio/audio_manager_unittest.cc b/media/audio/audio_manager_unittest.cc
index 7a5f3a50..c4940178 100644
--- a/media/audio/audio_manager_unittest.cc
+++ b/media/audio/audio_manager_unittest.cc
@@ -56,7 +56,7 @@
 #if defined(USE_CRAS)
 #include "chromeos/audio/audio_devices_pref_handler_stub.h"
 #include "chromeos/audio/cras_audio_handler.h"
-#include "chromeos/dbus/dbus_switches.h"
+#include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cras_audio_client.h"
 #include "media/audio/cras/audio_manager_cras.h"
diff --git a/media/base/android/media_drm_bridge_client.h b/media/base/android/media_drm_bridge_client.h
index dca8161..0b154b924 100644
--- a/media/base/android/media_drm_bridge_client.h
+++ b/media/base/android/media_drm_bridge_client.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <string>
+#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -36,7 +37,7 @@
 // provide customized additions to Android's media handling.
 class MEDIA_EXPORT MediaDrmBridgeClient {
  public:
-  typedef base::hash_map<std::string, UUID> KeySystemUuidMap;
+  typedef std::unordered_map<std::string, UUID> KeySystemUuidMap;
 
   MediaDrmBridgeClient();
   virtual ~MediaDrmBridgeClient();
diff --git a/media/base/key_systems.cc b/media/base/key_systems.cc
index 6543afdc..b18aaf28 100644
--- a/media/base/key_systems.cc
+++ b/media/base/key_systems.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 
 #include <memory>
+#include <unordered_map>
 
 #include "base/containers/hash_tables.h"
 #include "base/logging.h"
@@ -285,11 +286,11 @@
   bool IsValidMimeTypeCodecsCombination(const std::string& mime_type,
                                         SupportedCodecs codecs) const;
 
-  typedef base::hash_map<std::string, std::unique_ptr<KeySystemProperties>>
+  typedef std::unordered_map<std::string, std::unique_ptr<KeySystemProperties>>
       KeySystemPropertiesMap;
-  typedef base::hash_map<std::string, SupportedCodecs> MimeTypeToCodecsMap;
-  typedef base::hash_map<std::string, EmeCodec> CodecMap;
-  typedef base::hash_map<std::string, EmeInitDataType> InitDataTypesMap;
+  typedef std::unordered_map<std::string, SupportedCodecs> MimeTypeToCodecsMap;
+  typedef std::unordered_map<std::string, EmeCodec> CodecMap;
+  typedef std::unordered_map<std::string, EmeInitDataType> InitDataTypesMap;
 
   // TODO(sandersd): Separate container enum from codec mask value.
   // http://crbug.com/417440
diff --git a/media/webrtc/audio_processor.cc b/media/webrtc/audio_processor.cc
index 448bd03..299621d 100644
--- a/media/webrtc/audio_processor.cc
+++ b/media/webrtc/audio_processor.cc
@@ -261,18 +261,6 @@
     DCHECK_EQ(err, 0);
   }
 
-  // Typing detection setup.
-  if (settings_.typing_detection) {
-    typing_detector_ = std::make_unique<webrtc::TypingDetection>();
-    int err = audio_processing_->voice_detection()->Enable(true);
-    err |= audio_processing_->voice_detection()->set_likelihood(
-        webrtc::VoiceDetection::kVeryLowLikelihood);
-    DCHECK_EQ(err, 0);
-
-    // Configure the update period to 1s (100 * 10ms) in the typing detector.
-    typing_detector_->SetParameters(0, 0, 0, 0, 0, 100);
-  }
-
   // AGC setup part 2.
   if (settings_.automatic_gain_control != AutomaticGainControlType::kDisabled) {
     int err = audio_processing_->gain_control()->set_mode(
@@ -289,6 +277,15 @@
 
   webrtc::AudioProcessing::Config apm_config = audio_processing_->GetConfig();
 
+  // Typing detection setup.
+  if (settings_.typing_detection) {
+    typing_detector_ = std::make_unique<webrtc::TypingDetection>();
+    // Configure the update period to 1s (100 * 10ms) in the typing detector.
+    typing_detector_->SetParameters(0, 0, 0, 0, 0, 100);
+
+    apm_config.voice_detection.enabled = true;
+  }
+
   // AEC setup part 2.
   apm_config.echo_canceller.enabled =
       settings_.echo_cancellation == EchoCancellationType::kAec2 ||
@@ -370,10 +367,12 @@
 
 void AudioProcessor::UpdateTypingDetected(bool key_pressed) {
   if (typing_detector_) {
-    webrtc::VoiceDetection* vad = audio_processing_->voice_detection();
-    DCHECK(vad->is_enabled());
-    typing_detected_ =
-        typing_detector_->Process(key_pressed, vad->stream_has_voice());
+    // Ignore remote tracks to avoid unnecessary stats computation.
+    auto voice_detected =
+        audio_processing_->GetStatistics(false /* has_remote_tracks */)
+            .voice_detected;
+    DCHECK(voice_detected.has_value());
+    typing_detected_ = typing_detector_->Process(key_pressed, *voice_detected);
   }
 }
 
diff --git a/media/webrtc/audio_processor_unittest.cc b/media/webrtc/audio_processor_unittest.cc
index 4fb9964..7213b08 100644
--- a/media/webrtc/audio_processor_unittest.cc
+++ b/media/webrtc/audio_processor_unittest.cc
@@ -132,6 +132,7 @@
     EXPECT_TRUE(ap_config.echo_canceller.enabled);
     EXPECT_FALSE(ap_config.echo_canceller.mobile_mode);
     EXPECT_TRUE(ap_config.high_pass_filter.enabled);
+    EXPECT_TRUE(ap_config.voice_detection.enabled);
 
     EXPECT_TRUE(audio_processing->noise_suppression()->is_enabled());
     EXPECT_TRUE(audio_processing->noise_suppression()->level() ==
@@ -139,9 +140,6 @@
     EXPECT_TRUE(audio_processing->gain_control()->is_enabled());
     EXPECT_TRUE(audio_processing->gain_control()->mode() ==
                 webrtc::GainControl::kAdaptiveAnalog);
-    EXPECT_TRUE(audio_processing->voice_detection()->is_enabled());
-    EXPECT_TRUE(audio_processing->voice_detection()->likelihood() ==
-                webrtc::VoiceDetection::kVeryLowLikelihood);
   }
 
   AudioProcessingSettings GetEnabledAudioProcessingSettings() const {
diff --git a/services/device/BUILD.gn b/services/device/BUILD.gn
index 406a60c89..ae1b02b 100644
--- a/services/device/BUILD.gn
+++ b/services/device/BUILD.gn
@@ -207,7 +207,10 @@
       sources += [ "serial/serial_io_handler_posix_unittest.cc" ]
     }
 
-    deps += [ "//services/device/serial" ]
+    deps += [
+      "//services/device/serial",
+      "//services/device/serial:test_support",
+    ]
   }
 
   if (is_win) {
diff --git a/services/device/public/mojom/serial.mojom b/services/device/public/mojom/serial.mojom
index e9712ac..b003419 100644
--- a/services/device/public/mojom/serial.mojom
+++ b/services/device/public/mojom/serial.mojom
@@ -4,7 +4,10 @@
 
 module device.mojom;
 
+import "mojo/public/mojom/base/unguessable_token.mojom";
+
 struct SerialPortInfo {
+  mojo_base.mojom.UnguessableToken token;
   string path;
   uint16 vendor_id;
   bool has_vendor_id = false;
@@ -87,7 +90,7 @@
 // Discovers and enumerates serial devices available to the host.
 interface SerialPortManager {
   GetDevices() => (array<SerialPortInfo> devices);
-  GetPort(string path, SerialPort& port_request);
+  GetPort(mojo_base.mojom.UnguessableToken token, SerialPort& port_request);
 };
 
 // Performs asynchronous I/O on serial devices.
diff --git a/services/device/serial/BUILD.gn b/services/device/serial/BUILD.gn
index c64a10ee..428194e 100644
--- a/services/device/serial/BUILD.gn
+++ b/services/device/serial/BUILD.gn
@@ -15,6 +15,7 @@
 
   source_set("serial") {
     visibility = [
+      ":test_support",
       "//services/device:lib",
       "//services/device:tests",
     ]
@@ -84,4 +85,18 @@
       ]
     }
   }
+
+  static_library("test_support") {
+    testonly = true
+
+    sources = [
+      "fake_serial_device_enumerator.cc",
+      "fake_serial_device_enumerator.h",
+    ]
+
+    deps = [
+      ":serial",
+      "//base",
+    ]
+  }
 }
diff --git a/services/device/serial/fake_serial_device_enumerator.cc b/services/device/serial/fake_serial_device_enumerator.cc
new file mode 100644
index 0000000..02c74e9
--- /dev/null
+++ b/services/device/serial/fake_serial_device_enumerator.cc
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/device/serial/fake_serial_device_enumerator.h"
+
+#include <utility>
+
+#include "base/stl_util.h"
+
+namespace device {
+
+FakeSerialEnumerator::FakeSerialEnumerator() = default;
+
+FakeSerialEnumerator::~FakeSerialEnumerator() = default;
+
+bool FakeSerialEnumerator::AddDevicePath(const std::string& path) {
+  if (base::ContainsValue(device_paths_, path))
+    return false;
+
+  device_paths_.push_back(path);
+  return true;
+}
+
+std::vector<mojom::SerialPortInfoPtr> FakeSerialEnumerator::GetDevices() {
+  std::vector<device::mojom::SerialPortInfoPtr> devices;
+  for (const auto& path : device_paths_) {
+    auto device = device::mojom::SerialPortInfo::New();
+    device->token = GetTokenFromPath(path);
+    device->path = path;
+    devices.push_back(std::move(device));
+  }
+  return devices;
+}
+
+}  // namespace device
diff --git a/services/device/serial/fake_serial_device_enumerator.h b/services/device/serial/fake_serial_device_enumerator.h
new file mode 100644
index 0000000..5ec3aa0
--- /dev/null
+++ b/services/device/serial/fake_serial_device_enumerator.h
@@ -0,0 +1,32 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_DEVICE_SERIAL_FAKE_SERIAL_DEVICE_ENUMERATOR_H_
+#define SERVICES_DEVICE_SERIAL_FAKE_SERIAL_DEVICE_ENUMERATOR_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "services/device/serial/serial_device_enumerator.h"
+
+namespace device {
+
+class FakeSerialEnumerator : public SerialDeviceEnumerator {
+ public:
+  FakeSerialEnumerator();
+  ~FakeSerialEnumerator() override;
+
+  bool AddDevicePath(const std::string& path);
+
+  std::vector<mojom::SerialPortInfoPtr> GetDevices() override;
+
+ private:
+  std::vector<std::string> device_paths_;
+  DISALLOW_COPY_AND_ASSIGN(FakeSerialEnumerator);
+};
+
+}  // namespace device
+
+#endif  // SERVICES_DEVICE_SERIAL_FAKE_SERIAL_DEVICE_ENUMERATOR_H_
diff --git a/services/device/serial/serial_device_enumerator.cc b/services/device/serial/serial_device_enumerator.cc
index a34cc556..c4f30ec6 100644
--- a/services/device/serial/serial_device_enumerator.cc
+++ b/services/device/serial/serial_device_enumerator.cc
@@ -4,10 +4,35 @@
 
 #include "services/device/serial/serial_device_enumerator.h"
 
+#include <utility>
+
+#include "base/unguessable_token.h"
+
 namespace device {
 
 SerialDeviceEnumerator::SerialDeviceEnumerator() = default;
 
 SerialDeviceEnumerator::~SerialDeviceEnumerator() = default;
 
+base::Optional<std::string> SerialDeviceEnumerator::GetPathFromToken(
+    const base::UnguessableToken& token) {
+  auto it = token_path_map_.find(token);
+  if (it == token_path_map_.end())
+    return base::nullopt;
+
+  return it->second;
+}
+
+const base::UnguessableToken& SerialDeviceEnumerator::GetTokenFromPath(
+    const std::string& path) {
+  for (const auto& pair : token_path_map_) {
+    if (pair.second == path)
+      return pair.first;
+  }
+  // A new serial path.
+  return token_path_map_
+      .insert(std::make_pair(base::UnguessableToken::Create(), path))
+      .first->first;
+}
+
 }  // namespace device
diff --git a/services/device/serial/serial_device_enumerator.h b/services/device/serial/serial_device_enumerator.h
index 0f105c0d..5482f936 100644
--- a/services/device/serial/serial_device_enumerator.h
+++ b/services/device/serial/serial_device_enumerator.h
@@ -5,21 +5,37 @@
 #ifndef SERVICES_DEVICE_SERIAL_SERIAL_DEVICE_ENUMERATOR_H_
 #define SERVICES_DEVICE_SERIAL_SERIAL_DEVICE_ENUMERATOR_H_
 
+#include <map>
 #include <memory>
+#include <string>
+#include <vector>
 
+#include "base/optional.h"
 #include "services/device/public/mojom/serial.mojom.h"
+#include "services/device/serial/serial_io_handler.h"
 
 namespace device {
 
 // Discovers and enumerates serial devices available to the host.
 class SerialDeviceEnumerator {
  public:
+  using TokenPathMap = std::map<base::UnguessableToken, std::string>;
+
   static std::unique_ptr<SerialDeviceEnumerator> Create();
 
   SerialDeviceEnumerator();
   virtual ~SerialDeviceEnumerator();
 
   virtual std::vector<mojom::SerialPortInfoPtr> GetDevices() = 0;
+
+  base::Optional<std::string> GetPathFromToken(
+      const base::UnguessableToken& token);
+
+ protected:
+  const base::UnguessableToken& GetTokenFromPath(const std::string& path);
+
+ private:
+  TokenPathMap token_path_map_;
 };
 
 }  // namespace device
diff --git a/services/device/serial/serial_device_enumerator_linux.cc b/services/device/serial/serial_device_enumerator_linux.cc
index a59e4ab..a4f7bb79 100644
--- a/services/device/serial/serial_device_enumerator_linux.cc
+++ b/services/device/serial/serial_device_enumerator_linux.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
@@ -71,6 +72,7 @@
     const char* bus = udev_device_get_property_value(device.get(), kHostBusKey);
     if (path != NULL && bus != NULL) {
       auto info = mojom::SerialPortInfo::New();
+      info->token = GetTokenFromPath(path);
       info->path = path;
 
       const char* vendor_id =
diff --git a/services/device/serial/serial_device_enumerator_linux.h b/services/device/serial/serial_device_enumerator_linux.h
index edcb9fa..d1ee7aa 100644
--- a/services/device/serial/serial_device_enumerator_linux.h
+++ b/services/device/serial/serial_device_enumerator_linux.h
@@ -5,6 +5,8 @@
 #ifndef SERVICES_DEVICE_SERIAL_SERIAL_DEVICE_ENUMERATOR_LINUX_H_
 #define SERVICES_DEVICE_SERIAL_SERIAL_DEVICE_ENUMERATOR_LINUX_H_
 
+#include <vector>
+
 #include "base/macros.h"
 #include "device/udev_linux/scoped_udev.h"
 #include "services/device/serial/serial_device_enumerator.h"
diff --git a/services/device/serial/serial_device_enumerator_mac.cc b/services/device/serial/serial_device_enumerator_mac.cc
index d3c557e4..aed6f0f 100644
--- a/services/device/serial/serial_device_enumerator_mac.cc
+++ b/services/device/serial/serial_device_enumerator_mac.cc
@@ -10,8 +10,11 @@
 
 #include <algorithm>
 #include <memory>
+#include <set>
+#include <string>
 #include <unordered_set>
 #include <utility>
+#include <vector>
 
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
@@ -99,10 +102,46 @@
   return std::min(std::max(value, min), max);
 }
 
+}  // namespace
+
+// static
+std::unique_ptr<SerialDeviceEnumerator> SerialDeviceEnumerator::Create() {
+  return std::make_unique<SerialDeviceEnumeratorMac>();
+}
+
+SerialDeviceEnumeratorMac::SerialDeviceEnumeratorMac() {}
+
+SerialDeviceEnumeratorMac::~SerialDeviceEnumeratorMac() {}
+
+std::vector<mojom::SerialPortInfoPtr> SerialDeviceEnumeratorMac::GetDevices() {
+  std::vector<mojom::SerialPortInfoPtr> devices = GetDevicesNew();
+  std::vector<mojom::SerialPortInfoPtr> old_devices = GetDevicesOld();
+
+  base::UmaHistogramSparse("Hardware.Serial.NewMinusOldDeviceListSize",
+                           Clamp(devices.size() - old_devices.size(), -10, 10));
+
+  // Add devices found from both the new and old methods of enumeration. If a
+  // device is found using both the new and the old enumeration method, then we
+  // take the device from the new enumeration method because it's able to
+  // collect more information. We do this by inserting the new devices first,
+  // because insertions are ignored if the key already exists.
+  std::unordered_set<std::string> devices_seen;
+  for (const auto& device : devices) {
+    bool inserted = devices_seen.insert(device->path).second;
+    DCHECK(inserted);
+  }
+  for (auto& device : old_devices) {
+    if (devices_seen.insert(device->path).second)
+      devices.push_back(std::move(device));
+  }
+  return devices;
+}
+
 // Returns an array of devices as retrieved through the new method of
 // enumerating serial devices (IOKit).  This new method gives more information
 // about the devices than the old method.
-std::vector<mojom::SerialPortInfoPtr> GetDevicesNew() {
+std::vector<mojom::SerialPortInfoPtr>
+SerialDeviceEnumeratorMac::GetDevicesNew() {
   std::vector<mojom::SerialPortInfoPtr> devices;
 
   base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
@@ -151,6 +190,7 @@
     if (GetStringProperty(scoped_device.get(), CFSTR(kIODialinDeviceKey),
                           &dialinDevice)) {
       mojom::SerialPortInfoPtr dialin_info = callout_info.Clone();
+      dialin_info->token = GetTokenFromPath(dialinDevice);
       dialin_info->path = dialinDevice;
       devices.push_back(std::move(dialin_info));
     }
@@ -158,6 +198,7 @@
     std::string calloutDevice;
     if (GetStringProperty(scoped_device.get(), CFSTR(kIOCalloutDeviceKey),
                           &calloutDevice)) {
+      callout_info->token = GetTokenFromPath(calloutDevice);
       callout_info->path = calloutDevice;
       devices.push_back(std::move(callout_info));
     }
@@ -169,7 +210,8 @@
 // Returns an array of devices as retrieved through the old method of
 // enumerating serial devices (pattern matching in /dev/). This old method gives
 // less information about the devices than the new method.
-std::vector<mojom::SerialPortInfoPtr> GetDevicesOld() {
+std::vector<mojom::SerialPortInfoPtr>
+SerialDeviceEnumeratorMac::GetDevicesOld() {
   const base::FilePath kDevRoot("/dev");
   const int kFilesAndSymLinks =
       base::FileEnumerator::FILES | base::FileEnumerator::SHOW_SYM_LINKS;
@@ -196,6 +238,8 @@
     for (; i != valid_patterns.end(); ++i) {
       if (base::MatchPattern(next_device, *i)) {
         auto info = mojom::SerialPortInfo::New();
+
+        info->token = GetTokenFromPath(next_device);
         info->path = next_device;
         devices.push_back(std::move(info));
         break;
@@ -205,39 +249,4 @@
   return devices;
 }
 
-}  // namespace
-
-// static
-std::unique_ptr<SerialDeviceEnumerator> SerialDeviceEnumerator::Create() {
-  return std::make_unique<SerialDeviceEnumeratorMac>();
-}
-
-SerialDeviceEnumeratorMac::SerialDeviceEnumeratorMac() {}
-
-SerialDeviceEnumeratorMac::~SerialDeviceEnumeratorMac() {}
-
-std::vector<mojom::SerialPortInfoPtr> SerialDeviceEnumeratorMac::GetDevices() {
-  std::vector<mojom::SerialPortInfoPtr> devices = GetDevicesNew();
-  std::vector<mojom::SerialPortInfoPtr> old_devices = GetDevicesOld();
-
-  base::UmaHistogramSparse("Hardware.Serial.NewMinusOldDeviceListSize",
-                           Clamp(devices.size() - old_devices.size(), -10, 10));
-
-  // Add devices found from both the new and old methods of enumeration. If a
-  // device is found using both the new and the old enumeration method, then we
-  // take the device from the new enumeration method because it's able to
-  // collect more information. We do this by inserting the new devices first,
-  // because insertions are ignored if the key already exists.
-  std::unordered_set<std::string> devices_seen;
-  for (const auto& device : devices) {
-    bool inserted = devices_seen.insert(device->path).second;
-    DCHECK(inserted);
-  }
-  for (auto& device : old_devices) {
-    if (devices_seen.insert(device->path).second)
-      devices.push_back(std::move(device));
-  }
-  return devices;
-}
-
 }  // namespace device
diff --git a/services/device/serial/serial_device_enumerator_mac.h b/services/device/serial/serial_device_enumerator_mac.h
index e9c79513..284a3b6b 100644
--- a/services/device/serial/serial_device_enumerator_mac.h
+++ b/services/device/serial/serial_device_enumerator_mac.h
@@ -5,6 +5,8 @@
 #ifndef SERVICES_DEVICE_SERIAL_SERIAL_DEVICE_ENUMERATOR_MAC_H_
 #define SERVICES_DEVICE_SERIAL_SERIAL_DEVICE_ENUMERATOR_MAC_H_
 
+#include <vector>
+
 #include "base/macros.h"
 #include "services/device/serial/serial_device_enumerator.h"
 
@@ -20,6 +22,9 @@
   std::vector<mojom::SerialPortInfoPtr> GetDevices() override;
 
  private:
+  std::vector<mojom::SerialPortInfoPtr> GetDevicesNew();
+  std::vector<mojom::SerialPortInfoPtr> GetDevicesOld();
+
   DISALLOW_COPY_AND_ASSIGN(SerialDeviceEnumeratorMac);
 };
 
diff --git a/services/device/serial/serial_device_enumerator_win.cc b/services/device/serial/serial_device_enumerator_win.cc
index 5d317381..b019aba 100644
--- a/services/device/serial/serial_device_enumerator_win.cc
+++ b/services/device/serial/serial_device_enumerator_win.cc
@@ -10,8 +10,11 @@
 #include <setupapi.h>
 #include <stdint.h>
 
+#include <algorithm>
 #include <memory>
+#include <string>
 #include <unordered_set>
+#include <utility>
 
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/string_number_conversions.h"
@@ -87,75 +90,6 @@
   return std::min(std::max(value, min), max);
 }
 
-// Returns an array of devices as retrieved through the new method of
-// enumerating serial devices (SetupDi).  This new method gives more information
-// about the devices than the old method.
-std::vector<mojom::SerialPortInfoPtr> GetDevicesNew() {
-  std::vector<mojom::SerialPortInfoPtr> devices;
-
-  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
-  // Make a device interface query to find all serial devices.
-  HDEVINFO dev_info =
-      SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, 0, 0, DIGCF_PRESENT);
-  if (dev_info == INVALID_HANDLE_VALUE)
-    return devices;
-
-  SP_DEVINFO_DATA dev_info_data;
-  dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
-  for (DWORD i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
-    std::string friendly_name, com_port;
-    // SPDRP_FRIENDLYNAME looks like "USB_SERIAL_PORT (COM3)".
-    if (!GetProperty(dev_info, dev_info_data, SPDRP_FRIENDLYNAME,
-                     &friendly_name) ||
-        !GetCOMPort(friendly_name, &com_port))
-      // In Windows, the COM port is the path used to uniquely identify the
-      // serial device. If the COM can't be found, ignore the device.
-      continue;
-
-    auto info = mojom::SerialPortInfo::New();
-    info->path = com_port;
-
-    std::string display_name;
-    if (GetDisplayName(friendly_name, &display_name))
-      info->display_name = std::move(display_name);
-
-    std::string hardware_id;
-    // SPDRP_HARDWAREID looks like "FTDIBUS\COMPORT&VID_0403&PID_6001".
-    if (GetProperty(dev_info, dev_info_data, SPDRP_HARDWAREID, &hardware_id)) {
-      uint32_t vendor_id, product_id;
-      if (GetVendorID(hardware_id, &vendor_id)) {
-        info->has_vendor_id = true;
-        info->vendor_id = vendor_id;
-      }
-      if (GetProductID(hardware_id, &product_id)) {
-        info->has_product_id = true;
-        info->product_id = product_id;
-      }
-    }
-
-    devices.push_back(std::move(info));
-  }
-
-  SetupDiDestroyDeviceInfoList(dev_info);
-  return devices;
-}
-
-// Returns an array of devices as retrieved through the old method of
-// enumerating serial devices (searching the registry). This old method gives
-// less information about the devices than the new method.
-std::vector<mojom::SerialPortInfoPtr> GetDevicesOld() {
-  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
-  base::win::RegistryValueIterator iter_key(
-      HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM\\");
-  std::vector<mojom::SerialPortInfoPtr> devices;
-  for (; iter_key.Valid(); ++iter_key) {
-    auto info = mojom::SerialPortInfo::New();
-    info->path = base::UTF16ToASCII(iter_key.Value());
-    devices.push_back(std::move(info));
-  }
-  return devices;
-}
-
 }  // namespace
 
 // static
@@ -191,4 +125,77 @@
   return devices;
 }
 
+// Returns an array of devices as retrieved through the new method of
+// enumerating serial devices (SetupDi).  This new method gives more information
+// about the devices than the old method.
+std::vector<mojom::SerialPortInfoPtr>
+SerialDeviceEnumeratorWin::GetDevicesNew() {
+  std::vector<mojom::SerialPortInfoPtr> devices;
+
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
+  // Make a device interface query to find all serial devices.
+  HDEVINFO dev_info =
+      SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, 0, 0, DIGCF_PRESENT);
+  if (dev_info == INVALID_HANDLE_VALUE)
+    return devices;
+
+  SP_DEVINFO_DATA dev_info_data;
+  dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
+  for (DWORD i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
+    std::string friendly_name, com_port;
+    // SPDRP_FRIENDLYNAME looks like "USB_SERIAL_PORT (COM3)".
+    if (!GetProperty(dev_info, dev_info_data, SPDRP_FRIENDLYNAME,
+                     &friendly_name) ||
+        !GetCOMPort(friendly_name, &com_port))
+      // In Windows, the COM port is the path used to uniquely identify the
+      // serial device. If the COM can't be found, ignore the device.
+      continue;
+
+    auto info = mojom::SerialPortInfo::New();
+    info->token = GetTokenFromPath(com_port);
+    info->path = com_port;
+
+    std::string display_name;
+    if (GetDisplayName(friendly_name, &display_name))
+      info->display_name = std::move(display_name);
+
+    std::string hardware_id;
+    // SPDRP_HARDWAREID looks like "FTDIBUS\COMPORT&VID_0403&PID_6001".
+    if (GetProperty(dev_info, dev_info_data, SPDRP_HARDWAREID, &hardware_id)) {
+      uint32_t vendor_id, product_id;
+      if (GetVendorID(hardware_id, &vendor_id)) {
+        info->has_vendor_id = true;
+        info->vendor_id = vendor_id;
+      }
+      if (GetProductID(hardware_id, &product_id)) {
+        info->has_product_id = true;
+        info->product_id = product_id;
+      }
+    }
+
+    devices.push_back(std::move(info));
+  }
+
+  SetupDiDestroyDeviceInfoList(dev_info);
+  return devices;
+}
+
+// Returns an array of devices as retrieved through the old method of
+// enumerating serial devices (searching the registry). This old method gives
+// less information about the devices than the new method.
+std::vector<mojom::SerialPortInfoPtr>
+SerialDeviceEnumeratorWin::GetDevicesOld() {
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
+  base::win::RegistryValueIterator iter_key(
+      HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM\\");
+  std::vector<mojom::SerialPortInfoPtr> devices;
+  for (; iter_key.Valid(); ++iter_key) {
+    auto info = mojom::SerialPortInfo::New();
+    info->path = base::UTF16ToASCII(iter_key.Value());
+    info->token = GetTokenFromPath(info->path);
+    devices.push_back(std::move(info));
+  }
+  return devices;
+}
+
 }  // namespace device
diff --git a/services/device/serial/serial_device_enumerator_win.h b/services/device/serial/serial_device_enumerator_win.h
index 9b76a5f..745db97 100644
--- a/services/device/serial/serial_device_enumerator_win.h
+++ b/services/device/serial/serial_device_enumerator_win.h
@@ -5,6 +5,8 @@
 #ifndef SERVICES_DEVICE_SERIAL_SERIAL_DEVICE_ENUMERATOR_WIN_H_
 #define SERVICES_DEVICE_SERIAL_SERIAL_DEVICE_ENUMERATOR_WIN_H_
 
+#include <vector>
+
 #include "base/macros.h"
 #include "services/device/serial/serial_device_enumerator.h"
 
@@ -20,6 +22,9 @@
   std::vector<mojom::SerialPortInfoPtr> GetDevices() override;
 
  private:
+  std::vector<mojom::SerialPortInfoPtr> GetDevicesNew();
+  std::vector<mojom::SerialPortInfoPtr> GetDevicesOld();
+
   DISALLOW_COPY_AND_ASSIGN(SerialDeviceEnumeratorWin);
 };
 
diff --git a/services/device/serial/serial_io_handler.cc b/services/device/serial/serial_io_handler.cc
index 94542ef..379daafa 100644
--- a/services/device/serial/serial_io_handler.cc
+++ b/services/device/serial/serial_io_handler.cc
@@ -23,8 +23,9 @@
 namespace device {
 
 SerialIoHandler::SerialIoHandler(
+    const std::string& port,
     scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
-    : ui_thread_task_runner_(ui_thread_task_runner) {
+    : port_(port), ui_thread_task_runner_(ui_thread_task_runner) {
   options_.bitrate = 9600;
   options_.data_bits = mojom::SerialDataBits::EIGHT;
   options_.parity_bit = mojom::SerialParityBit::NO_PARITY;
@@ -38,15 +39,14 @@
   Close();
 }
 
-void SerialIoHandler::Open(const std::string& port,
-                           const mojom::SerialConnectionOptions& options,
+void SerialIoHandler::Open(const mojom::SerialConnectionOptions& options,
                            OpenCompleteCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!open_complete_);
+  DCHECK(!port_.empty());
   open_complete_ = std::move(callback);
   DCHECK(ui_thread_task_runner_.get());
   MergeConnectionOptions(options);
-  port_ = port;
 
 #if defined(OS_CHROMEOS)
   chromeos::PermissionBrokerClient* client =
@@ -58,7 +58,7 @@
   ui_thread_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&chromeos::PermissionBrokerClient::OpenPath,
-                     base::Unretained(client), port,
+                     base::Unretained(client), port_,
                      base::BindRepeating(&SerialIoHandler::OnPathOpened, this,
                                          task_runner),
                      base::BindRepeating(&SerialIoHandler::OnPathOpenError,
@@ -67,7 +67,7 @@
   base::PostTaskWithTraits(
       FROM_HERE,
       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-      base::BindOnce(&SerialIoHandler::StartOpen, this, port,
+      base::BindOnce(&SerialIoHandler::StartOpen, this,
                      base::ThreadTaskRunnerHandle::Get()));
 #endif  // defined(OS_CHROMEOS)
 }
@@ -124,15 +124,15 @@
 }
 
 void SerialIoHandler::StartOpen(
-    const std::string& port,
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) {
   DCHECK(open_complete_);
   DCHECK(!file_.IsValid());
   // It's the responsibility of the API wrapper around SerialIoHandler to
   // validate the supplied path against the set of valid port names, and
   // it is a reasonable assumption that serial port names are ASCII.
-  DCHECK(base::IsStringASCII(port));
-  base::FilePath path(base::FilePath::FromUTF8Unsafe(MaybeFixUpPortName(port)));
+  DCHECK(base::IsStringASCII(port_));
+  base::FilePath path(
+      base::FilePath::FromUTF8Unsafe(MaybeFixUpPortName(port_)));
   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
               base::File::FLAG_EXCLUSIVE_READ | base::File::FLAG_WRITE |
               base::File::FLAG_EXCLUSIVE_WRITE | base::File::FLAG_ASYNC |
diff --git a/services/device/serial/serial_io_handler.h b/services/device/serial/serial_io_handler.h
index ce75809..6058f0e 100644
--- a/services/device/serial/serial_io_handler.h
+++ b/services/device/serial/serial_io_handler.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <memory>
+#include <string>
 
 #include "base/callback.h"
 #include "base/files/file.h"
@@ -30,13 +31,13 @@
  public:
   // Constructs an instance of some platform-specific subclass.
   static scoped_refptr<SerialIoHandler> Create(
+      const std::string& port,
       scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
 
   typedef base::OnceCallback<void(bool success)> OpenCompleteCallback;
 
   // Initiates an asynchronous Open of the device.
-  virtual void Open(const std::string& port,
-                    const mojom::SerialConnectionOptions& options,
+  virtual void Open(const mojom::SerialConnectionOptions& options,
                     OpenCompleteCallback callback);
 
 #if defined(OS_CHROMEOS)
@@ -111,6 +112,7 @@
 
  protected:
   explicit SerialIoHandler(
+      const std::string& port,
       scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
   virtual ~SerialIoHandler();
 
@@ -209,8 +211,7 @@
   void MergeConnectionOptions(const mojom::SerialConnectionOptions& options);
 
   // Continues an Open operation on the FILE thread.
-  void StartOpen(const std::string& port,
-                 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
+  void StartOpen(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
 
   // Finalizes an Open operation (continued from StartOpen) on the IO thread.
   void FinishOpen(base::File file);
@@ -238,11 +239,11 @@
   // Callback to handle the completion of a pending Open() request.
   OpenCompleteCallback open_complete_;
 
+  const std::string port_;
+
   // On Chrome OS, PermissionBrokerClient should be called on the UI thread.
   scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_;
 
-  std::string port_;
-
   DISALLOW_COPY_AND_ASSIGN(SerialIoHandler);
 };
 
diff --git a/services/device/serial/serial_io_handler_posix.cc b/services/device/serial/serial_io_handler_posix.cc
index cfbe691..546efd4 100644
--- a/services/device/serial/serial_io_handler_posix.cc
+++ b/services/device/serial/serial_io_handler_posix.cc
@@ -7,6 +7,9 @@
 #include <sys/ioctl.h>
 #include <termios.h>
 
+#include <algorithm>
+#include <utility>
+
 #include "base/files/file_util.h"
 #include "base/posix/eintr_wrapper.h"
 #include "build/build_config.h"
@@ -114,8 +117,9 @@
 
 // static
 scoped_refptr<SerialIoHandler> SerialIoHandler::Create(
+    const std::string& port,
     scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) {
-  return new SerialIoHandlerPosix(ui_thread_task_runner);
+  return new SerialIoHandlerPosix(port, std::move(ui_thread_task_runner));
 }
 
 void SerialIoHandlerPosix::ReadImpl() {
@@ -291,8 +295,9 @@
 }
 
 SerialIoHandlerPosix::SerialIoHandlerPosix(
+    const std::string& port,
     scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
-    : SerialIoHandler(ui_thread_task_runner) {}
+    : SerialIoHandler(port, std::move(ui_thread_task_runner)) {}
 
 SerialIoHandlerPosix::~SerialIoHandlerPosix() = default;
 
diff --git a/services/device/serial/serial_io_handler_posix.h b/services/device/serial/serial_io_handler_posix.h
index d46d021..e74190f 100644
--- a/services/device/serial/serial_io_handler_posix.h
+++ b/services/device/serial/serial_io_handler_posix.h
@@ -6,6 +6,7 @@
 #define SERVICES_DEVICE_SERIAL_SERIAL_IO_HANDLER_POSIX_H_
 
 #include <memory>
+#include <string>
 
 #include "base/files/file_descriptor_watcher_posix.h"
 #include "base/macros.h"
@@ -47,6 +48,7 @@
   friend class SerialIoHandlerPosixTest;
 
   SerialIoHandlerPosix(
+      const std::string& port,
       scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
   ~SerialIoHandlerPosix() override;
 
diff --git a/services/device/serial/serial_io_handler_posix_unittest.cc b/services/device/serial/serial_io_handler_posix_unittest.cc
index b9ff041c..c0a34144fa 100644
--- a/services/device/serial/serial_io_handler_posix_unittest.cc
+++ b/services/device/serial/serial_io_handler_posix_unittest.cc
@@ -14,7 +14,7 @@
   SerialIoHandlerPosixTest() = default;
 
   void SetUp() override {
-    serial_io_handler_posix_ = new SerialIoHandlerPosix(nullptr);
+    serial_io_handler_posix_ = new SerialIoHandlerPosix("dummy-port", nullptr);
   }
 
   void Initialize(bool parity_check_enabled,
diff --git a/services/device/serial/serial_io_handler_win.cc b/services/device/serial/serial_io_handler_win.cc
index 74e1cec8..5fbad45 100644
--- a/services/device/serial/serial_io_handler_win.cc
+++ b/services/device/serial/serial_io_handler_win.cc
@@ -9,6 +9,8 @@
 #include <setupapi.h>
 #include <windows.h>
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop_current.h"
@@ -152,8 +154,9 @@
 
 // static
 scoped_refptr<SerialIoHandler> SerialIoHandler::Create(
+    const std::string& port,
     scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) {
-  return new SerialIoHandlerWin(ui_thread_task_runner);
+  return new SerialIoHandlerWin(port, std::move(ui_thread_task_runner));
 }
 
 class SerialIoHandlerWin::UiThreadHelper final
@@ -357,8 +360,9 @@
 }
 
 SerialIoHandlerWin::SerialIoHandlerWin(
+    const std::string& port,
     scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
-    : SerialIoHandler(ui_thread_task_runner),
+    : SerialIoHandler(port, std::move(ui_thread_task_runner)),
       event_mask_(0),
       is_comm_pending_(false),
       helper_(nullptr),
diff --git a/services/device/serial/serial_io_handler_win.h b/services/device/serial/serial_io_handler_win.h
index 4c34ca7a..44d9934c 100644
--- a/services/device/serial/serial_io_handler_win.h
+++ b/services/device/serial/serial_io_handler_win.h
@@ -6,6 +6,7 @@
 #define SERVICES_DEVICE_SERIAL_SERIAL_IO_HANDLER_WIN_H_
 
 #include <memory>
+#include <string>
 
 #include "base/macros.h"
 #include "base/message_loop/message_pump_for_io.h"
@@ -38,6 +39,7 @@
   friend class SerialIoHandler;
 
   explicit SerialIoHandlerWin(
+      const std::string& port,
       scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
   ~SerialIoHandlerWin() override;
 
diff --git a/services/device/serial/serial_port_impl.cc b/services/device/serial/serial_port_impl.cc
index ca74814..27f47fd 100644
--- a/services/device/serial/serial_port_impl.cc
+++ b/services/device/serial/serial_port_impl.cc
@@ -4,6 +4,9 @@
 
 #include "services/device/serial/serial_port_impl.h"
 
+#include <memory>
+#include <utility>
+
 #include "base/single_thread_task_runner.h"
 #include "base/task/post_task.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
@@ -25,14 +28,13 @@
 SerialPortImpl::SerialPortImpl(
     const std::string& path,
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
-    : path_(path),
-      io_handler_(device::SerialIoHandler::Create(ui_task_runner)) {}
+    : io_handler_(device::SerialIoHandler::Create(path, ui_task_runner)) {}
 
 SerialPortImpl::~SerialPortImpl() = default;
 
 void SerialPortImpl::Open(mojom::SerialConnectionOptionsPtr options,
                           OpenCallback callback) {
-  io_handler_->Open(path_, *options, std::move(callback));
+  io_handler_->Open(*options, std::move(callback));
 }
 
 void SerialPortImpl::Read(uint32_t bytes, ReadCallback callback) {
diff --git a/services/device/serial/serial_port_impl.h b/services/device/serial/serial_port_impl.h
index 5c82e23..504c67a7 100644
--- a/services/device/serial/serial_port_impl.h
+++ b/services/device/serial/serial_port_impl.h
@@ -5,6 +5,9 @@
 #ifndef SERVICES_DEVICE_SERIAL_SERIAL_PORT_IMPL_H_
 #define SERVICES_DEVICE_SERIAL_SERIAL_PORT_IMPL_H_
 
+#include <string>
+#include <vector>
+
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "services/device/public/mojom/serial.mojom.h"
@@ -28,9 +31,8 @@
       mojom::SerialPortRequest request,
       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
 
-  explicit SerialPortImpl(
-      const std::string& path,
-      scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
+  SerialPortImpl(const std::string& path,
+                 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
   ~SerialPortImpl() override;
 
  private:
@@ -51,7 +53,6 @@
   void SetBreak(SetBreakCallback callback) override;
   void ClearBreak(ClearBreakCallback callback) override;
 
-  std::string path_;
   scoped_refptr<SerialIoHandler> io_handler_;
 
   DISALLOW_COPY_AND_ASSIGN(SerialPortImpl);
diff --git a/services/device/serial/serial_port_impl_unittest.cc b/services/device/serial/serial_port_impl_unittest.cc
index e8c77a7..2e4405c7 100644
--- a/services/device/serial/serial_port_impl_unittest.cc
+++ b/services/device/serial/serial_port_impl_unittest.cc
@@ -36,7 +36,8 @@
 // TODO(leonhsl): figure out how to add more robust tests.
 TEST_F(SerialPortImplTest, SimpleConnectTest) {
   mojom::SerialPortPtr serial_port;
-  port_manager_->GetPort("", mojo::MakeRequest(&serial_port));
+  port_manager_->GetPort(base::UnguessableToken::Create(),
+                         mojo::MakeRequest(&serial_port));
   serial_port.FlushForTesting();
 }
 
diff --git a/services/device/serial/serial_port_manager_impl.cc b/services/device/serial/serial_port_manager_impl.cc
index 120a108..461378ef 100644
--- a/services/device/serial/serial_port_manager_impl.cc
+++ b/services/device/serial/serial_port_manager_impl.cc
@@ -4,6 +4,9 @@
 
 #include "services/device/serial/serial_port_manager_impl.h"
 
+#include <string>
+#include <utility>
+
 #include "base/sequenced_task_runner.h"
 #include "base/task/post_task.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
@@ -45,22 +48,32 @@
 SerialPortManagerImpl::SerialPortManagerImpl(
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
-    : enumerator_(device::SerialDeviceEnumerator::Create()),
+    : enumerator_(SerialDeviceEnumerator::Create()),
       io_task_runner_(std::move(io_task_runner)),
       ui_task_runner_(std::move(ui_task_runner)) {}
 
 SerialPortManagerImpl::~SerialPortManagerImpl() = default;
 
+void SerialPortManagerImpl::SetSerialEnumeratorForTesting(
+    std::unique_ptr<SerialDeviceEnumerator> fake_enumerator) {
+  DCHECK(fake_enumerator);
+  enumerator_ = std::move(fake_enumerator);
+}
+
 void SerialPortManagerImpl::GetDevices(GetDevicesCallback callback) {
   DCHECK(enumerator_);
   std::move(callback).Run(enumerator_->GetDevices());
 }
 
-void SerialPortManagerImpl::GetPort(const std::string& path,
+void SerialPortManagerImpl::GetPort(const base::UnguessableToken& token,
                                     mojom::SerialPortRequest request) {
-  io_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&SerialPortImpl::Create, path,
-                                std::move(request), ui_task_runner_));
+  DCHECK(enumerator_);
+  base::Optional<std::string> path = enumerator_->GetPathFromToken(token);
+  if (path) {
+    io_task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&SerialPortImpl::Create, *path,
+                                  std::move(request), ui_task_runner_));
+  }
 }
 
 }  // namespace device
diff --git a/services/device/serial/serial_port_manager_impl.h b/services/device/serial/serial_port_manager_impl.h
index 7cb6720e..476426d 100644
--- a/services/device/serial/serial_port_manager_impl.h
+++ b/services/device/serial/serial_port_manager_impl.h
@@ -13,6 +13,7 @@
 
 namespace base {
 class SingleThreadTaskRunner;
+class UnguessableToken;
 }
 
 namespace device {
@@ -33,10 +34,13 @@
       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
   ~SerialPortManagerImpl() override;
 
+  void SetSerialEnumeratorForTesting(
+      std::unique_ptr<SerialDeviceEnumerator> fake_enumerator);
+
  private:
   // mojom::SerialPortManager methods:
   void GetDevices(GetDevicesCallback callback) override;
-  void GetPort(const std::string& path,
+  void GetPort(const base::UnguessableToken& token,
                mojom::SerialPortRequest request) override;
 
   std::unique_ptr<SerialDeviceEnumerator> enumerator_;
diff --git a/services/device/serial/serial_port_manager_impl_unittest.cc b/services/device/serial/serial_port_manager_impl_unittest.cc
index f6f1a75..fe56766 100644
--- a/services/device/serial/serial_port_manager_impl_unittest.cc
+++ b/services/device/serial/serial_port_manager_impl_unittest.cc
@@ -4,42 +4,142 @@
 
 #include "services/device/serial/serial_port_manager_impl.h"
 
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
 #include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/task/post_task.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread.h"
 #include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/device/device_service_test_base.h"
 #include "services/device/public/mojom/constants.mojom.h"
 #include "services/device/public/mojom/serial.mojom.h"
+#include "services/device/serial/fake_serial_device_enumerator.h"
+#include "testing/gtest/include/gtest/gtest.h"
 
 namespace device {
 
 namespace {
+static const char kFakeDevicePath1[] = "/dev/fakeserialmojo";
+static const char kFakeDevicePath2[] = "\\\\COM800\\";
+
+void CreateAndBindOnBlockableRunner(
+    mojom::SerialPortManagerRequest request,
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
+  auto manager = std::make_unique<SerialPortManagerImpl>(
+      std::move(io_task_runner), std::move(ui_task_runner));
+  auto fake_enumerator = std::make_unique<FakeSerialEnumerator>();
+  fake_enumerator->AddDevicePath(kFakeDevicePath1);
+  fake_enumerator->AddDevicePath(kFakeDevicePath2);
+  manager->SetSerialEnumeratorForTesting(std::move(fake_enumerator));
+  mojo::MakeStrongBinding(std::move(manager), std::move(request));
+}
+
+void ExpectDevicesAndThen(const std::set<std::string>& expected_paths,
+                          base::OnceClosure continuation,
+                          std::vector<mojom::SerialPortInfoPtr> results) {
+  EXPECT_EQ(expected_paths.size(), results.size());
+  std::set<std::string> actual_paths;
+  for (size_t i = 0; i < results.size(); ++i)
+    actual_paths.insert(results[i]->path);
+  EXPECT_EQ(expected_paths, actual_paths);
+  std::move(continuation).Run();
+}
+
+void OnGotDevicesAndGetPort(mojom::SerialPortManagerPtr port_manager,
+                            base::OnceClosure continuation,
+                            std::vector<mojom::SerialPortInfoPtr> results) {
+  EXPECT_GT(results.size(), 0u);
+
+  mojom::SerialPortPtr serial_port;
+  port_manager->GetPort(results[0]->token, mojo::MakeRequest(&serial_port));
+  // Send a message on the pipe and wait for the response to make sure that the
+  // interface request was bound successfully.
+  serial_port.FlushForTesting();
+  EXPECT_FALSE(serial_port.encountered_error());
+  std::move(continuation).Run();
+}
+
+void OnGotDevicesForSimpleConnect(
+    mojom::SerialPortManagerPtr port_manager,
+    base::OnceClosure continuation,
+    std::vector<mojom::SerialPortInfoPtr> results) {
+  for (auto& device : results) {
+    mojom::SerialPortPtr serial_port;
+    port_manager->GetPort(device->token, mojo::MakeRequest(&serial_port));
+    // Send a message on the pipe and wait for the response to make sure that
+    // the interface request was bound successfully.
+    serial_port.FlushForTesting();
+    EXPECT_FALSE(serial_port.encountered_error());
+  }
+  std::move(continuation).Run();
+}
+
+}  // namespace
 
 class SerialPortManagerImplTest : public DeviceServiceTestBase {
  public:
-  SerialPortManagerImplTest() = default;
+  SerialPortManagerImplTest() {
+    blockable_runner_ = base::CreateSequencedTaskRunnerWithTraits(
+        {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
+  }
   ~SerialPortManagerImplTest() override = default;
 
  protected:
-  void SetUp() override {
-    DeviceServiceTestBase::SetUp();
-    connector()->BindInterface(mojom::kServiceName, &port_manager_);
+  void SetUp() override { DeviceServiceTestBase::SetUp(); }
+
+  void BindSerialPortManager(mojom::SerialPortManagerRequest request) {
+    blockable_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&CreateAndBindOnBlockableRunner,
+                                  std::move(request), io_thread_.task_runner(),
+                                  base::ThreadTaskRunnerHandle::Get()));
   }
 
-  void TearDown() override { port_manager_.reset(); }
-
-  mojom::SerialPortManagerPtr port_manager_;
+  scoped_refptr<base::SequencedTaskRunner> blockable_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(SerialPortManagerImplTest);
 };
 
-// This is to simply test that on Linux/Mac/Windows a client can connect to
-// Device Service and bind the serial SerialDeviceEnumerator interface
-// correctly.
-// TODO(leonhsl): figure out how to add more robust tests.
+// This is to simply test that we can enumerate devices on the platform without
+// hanging or crashing.
 TEST_F(SerialPortManagerImplTest, SimpleConnectTest) {
-  port_manager_.FlushForTesting();
+  mojom::SerialPortManagerPtr port_manager;
+  connector()->BindInterface(mojom::kServiceName, &port_manager);
+
+  base::RunLoop loop;
+  auto* manager = port_manager.get();
+  manager->GetDevices(base::BindOnce(&OnGotDevicesForSimpleConnect,
+                                     std::move(port_manager),
+                                     loop.QuitClosure()));
+  loop.Run();
 }
 
-}  // namespace
+TEST_F(SerialPortManagerImplTest, GetDevices) {
+  mojom::SerialPortManagerPtr port_manager;
+  BindSerialPortManager(mojo::MakeRequest(&port_manager));
+  std::set<std::string> expected_paths = {kFakeDevicePath1, kFakeDevicePath2};
+
+  base::RunLoop loop;
+  port_manager->GetDevices(base::BindOnce(&ExpectDevicesAndThen, expected_paths,
+                                          loop.QuitClosure()));
+  loop.Run();
+}
+
+TEST_F(SerialPortManagerImplTest, GetPort) {
+  mojom::SerialPortManagerPtr port_manager;
+  BindSerialPortManager(mojo::MakeRequest(&port_manager));
+
+  base::RunLoop loop;
+  auto* manager = port_manager.get();
+  manager->GetDevices(base::BindOnce(
+      &OnGotDevicesAndGetPort, std::move(port_manager), loop.QuitClosure()));
+  loop.Run();
+}
 
 }  // namespace device
diff --git a/services/identity/public/cpp/accounts_in_cookie_jar_info.cc b/services/identity/public/cpp/accounts_in_cookie_jar_info.cc
index 53e05cc9..a12fc34 100644
--- a/services/identity/public/cpp/accounts_in_cookie_jar_info.cc
+++ b/services/identity/public/cpp/accounts_in_cookie_jar_info.cc
@@ -10,17 +10,21 @@
 
 AccountsInCookieJarInfo::AccountsInCookieJarInfo(
     bool accounts_are_fresh_param,
-    const std::vector<AccountInfo>& accounts_param)
-    : accounts_are_fresh(accounts_are_fresh_param), accounts(accounts_param) {}
+    const std::vector<AccountInfo>& signed_in_accounts_param,
+    const std::vector<AccountInfo>& signed_out_accounts_param)
+    : accounts_are_fresh(accounts_are_fresh_param),
+      signed_in_accounts(signed_in_accounts_param),
+      signed_out_accounts(signed_out_accounts_param) {}
 
 AccountsInCookieJarInfo::AccountsInCookieJarInfo(
     const AccountsInCookieJarInfo& other) {
   if (this == &other)
     return;
   accounts_are_fresh = other.accounts_are_fresh;
-  accounts = other.accounts;
+  signed_in_accounts = other.signed_in_accounts;
+  signed_out_accounts = other.signed_out_accounts;
 }
 
 AccountsInCookieJarInfo::~AccountsInCookieJarInfo() = default;
 
-}  // namespace identity
\ No newline at end of file
+}  // namespace identity
diff --git a/services/identity/public/cpp/accounts_in_cookie_jar_info.h b/services/identity/public/cpp/accounts_in_cookie_jar_info.h
index acb5763d..fd6f0bc 100644
--- a/services/identity/public/cpp/accounts_in_cookie_jar_info.h
+++ b/services/identity/public/cpp/accounts_in_cookie_jar_info.h
@@ -17,12 +17,17 @@
   // updated.
   bool accounts_are_fresh;
 
-  // The current list of accounts from the cookie jar.
-  std::vector<AccountInfo> accounts;
+  // The current list of signed in accounts from the cookie jar.
+  std::vector<AccountInfo> signed_in_accounts;
+
+  // The current list of signed out accounts from the cookie jar.
+  std::vector<AccountInfo> signed_out_accounts;
 
   AccountsInCookieJarInfo();
-  AccountsInCookieJarInfo(bool accounts_are_fresh_param,
-                          const std::vector<AccountInfo>& accounts_param);
+  AccountsInCookieJarInfo(
+      bool accounts_are_fresh_param,
+      const std::vector<AccountInfo>& signed_in_accounts_param,
+      const std::vector<AccountInfo>& signed_out_accounts_param);
   AccountsInCookieJarInfo(const AccountsInCookieJarInfo& other);
   ~AccountsInCookieJarInfo();
 };
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc
index e9478e7..a2370c7 100644
--- a/services/identity/public/cpp/identity_manager.cc
+++ b/services/identity/public/cpp/identity_manager.cc
@@ -99,12 +99,14 @@
   // TODO(859882): Change this implementation to interact asynchronously with
   // GaiaCookieManagerService as detailed in
   // https://docs.google.com/document/d/1hcrJ44facCSHtMGBmPusvcoP-fAR300Hi-UFez8ffYQ/edit?pli=1#heading=h.w97eil1cygs2.
-  std::vector<gaia::ListedAccount> listed_accounts;
-  bool accounts_are_fresh =
-      gaia_cookie_manager_service_->ListAccounts(&listed_accounts, nullptr);
+  std::vector<gaia::ListedAccount> signed_in_accounts;
+  std::vector<gaia::ListedAccount> signed_out_accounts;
+  bool accounts_are_fresh = gaia_cookie_manager_service_->ListAccounts(
+      &signed_in_accounts, &signed_out_accounts);
 
-  return AccountsInCookieJarInfo(accounts_are_fresh,
-                                 ListedAccountsToAccountInfos(listed_accounts));
+  return AccountsInCookieJarInfo(
+      accounts_are_fresh, ListedAccountsToAccountInfos(signed_in_accounts),
+      ListedAccountsToAccountInfos(signed_out_accounts));
 }
 
 bool IdentityManager::HasAccountWithRefreshToken(
@@ -350,13 +352,25 @@
     observer.OnEndBatchOfRefreshTokenStateChanges();
 }
 
+void IdentityManager::OnAuthErrorChanged(
+    const std::string& account_id,
+    const GoogleServiceAuthError& auth_error) {
+  AccountInfo account_info =
+      GetAccountInfoForAccountWithRefreshToken(account_id);
+
+  for (auto& observer : observer_list_)
+    observer.OnErrorStateOfRefreshTokenUpdatedForAccount(account_info,
+                                                         auth_error);
+}
+
 void IdentityManager::OnGaiaAccountsInCookieUpdated(
-    const std::vector<gaia::ListedAccount>& accounts,
+    const std::vector<gaia::ListedAccount>& signed_in_accounts,
     const std::vector<gaia::ListedAccount>& signed_out_accounts,
     const GoogleServiceAuthError& error) {
   AccountsInCookieJarInfo accounts_in_cookie_jar_info(
       error == GoogleServiceAuthError::AuthErrorNone(),
-      ListedAccountsToAccountInfos(accounts));
+      ListedAccountsToAccountInfos(signed_in_accounts),
+      ListedAccountsToAccountInfos(signed_out_accounts));
 
   for (auto& observer : observer_list_) {
     observer.OnAccountsInCookieUpdated(accounts_in_cookie_jar_info, error);
diff --git a/services/identity/public/cpp/identity_manager.h b/services/identity/public/cpp/identity_manager.h
index 8f098e2..36d8f21 100644
--- a/services/identity/public/cpp/identity_manager.h
+++ b/services/identity/public/cpp/identity_manager.h
@@ -105,6 +105,14 @@
     virtual void OnRefreshTokenRemovedForAccount(
         const std::string& account_id) {}
 
+    // Called when the error state of the refresh token for |account_id| has
+    // changed. Note: It is always called after
+    // |OnRefreshTokenUpdatedForAccount| when the refresh token is updated. It
+    // is not called when the refresh token is removed.
+    virtual void OnErrorStateOfRefreshTokenUpdatedForAccount(
+        const AccountInfo& account_info,
+        const GoogleServiceAuthError& error) {}
+
     // Called after refresh tokens are loaded.
     // CAVEAT: On ChromeOS, this callback is not invoked during
     // startup in all cases. See https://crbug.com/749535, which
@@ -367,10 +375,12 @@
   void OnRefreshTokensLoaded() override;
   void OnStartBatchChanges() override;
   void OnEndBatchChanges() override;
+  void OnAuthErrorChanged(const std::string& account_id,
+                          const GoogleServiceAuthError& auth_error) override;
 
   // GaiaCookieManagerService::Observer:
   void OnGaiaAccountsInCookieUpdated(
-      const std::vector<gaia::ListedAccount>& accounts,
+      const std::vector<gaia::ListedAccount>& signed_in_accounts,
       const std::vector<gaia::ListedAccount>& signed_out_accounts,
       const GoogleServiceAuthError& error) override;
   void OnAddAccountToCookieCompleted(
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc
index d38d1d9..b04e00d 100644
--- a/services/identity/public/cpp/identity_manager_unittest.cc
+++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -226,6 +226,10 @@
       base::RepeatingCallback<void(const std::string&)> callback) {
     on_refresh_token_removed_callback_ = std::move(callback);
   }
+  void set_on_error_state_of_refresh_token_updated_callback(
+      base::OnceClosure callback) {
+    on_error_state_of_refresh_token_updated_callback_ = std::move(callback);
+  }
 
   void set_on_refresh_tokens_loaded_callback(base::OnceClosure callback) {
     on_refresh_tokens_loaded_callback_ = std::move(callback);
@@ -237,6 +241,14 @@
   const std::string& account_from_refresh_token_removed_callback() {
     return account_from_refresh_token_removed_callback_;
   }
+  const AccountInfo&
+  account_from_error_state_of_refresh_token_updated_callback() {
+    return account_from_error_state_of_refresh_token_updated_callback_;
+  }
+  const GoogleServiceAuthError&
+  error_from_error_state_of_refresh_token_updated_callback() const {
+    return error_from_error_state_of_refresh_token_updated_callback_;
+  }
 
   void set_on_accounts_in_cookie_updated_callback(base::OnceClosure callback) {
     on_accounts_in_cookie_updated_callback_ = std::move(callback);
@@ -300,6 +312,14 @@
     if (on_refresh_token_removed_callback_)
       on_refresh_token_removed_callback_.Run(account_id);
   }
+  void OnErrorStateOfRefreshTokenUpdatedForAccount(
+      const AccountInfo& account_info,
+      const GoogleServiceAuthError& error) override {
+    account_from_error_state_of_refresh_token_updated_callback_ = account_info;
+    error_from_error_state_of_refresh_token_updated_callback_ = error;
+    if (on_error_state_of_refresh_token_updated_callback_)
+      std::move(on_error_state_of_refresh_token_updated_callback_).Run();
+  }
   void OnRefreshTokensLoaded() override {
     if (on_refresh_tokens_loaded_callback_)
       std::move(on_refresh_tokens_loaded_callback_).Run();
@@ -337,12 +357,16 @@
   base::OnceClosure on_refresh_token_updated_callback_;
   base::RepeatingCallback<void(const std::string&)>
       on_refresh_token_removed_callback_;
+  base::OnceClosure on_error_state_of_refresh_token_updated_callback_;
   base::OnceClosure on_refresh_tokens_loaded_callback_;
   base::OnceClosure on_accounts_in_cookie_updated_callback_;
   AccountInfo primary_account_from_set_callback_;
   AccountInfo primary_account_from_cleared_callback_;
   AccountInfo account_from_refresh_token_updated_callback_;
   std::string account_from_refresh_token_removed_callback_;
+  AccountInfo account_from_error_state_of_refresh_token_updated_callback_;
+  GoogleServiceAuthError
+      error_from_error_state_of_refresh_token_updated_callback_;
   AccountsInCookieJarInfo accounts_info_from_cookie_change_callback_;
   std::string account_from_add_account_to_cookie_completed_callback_;
   GoogleServiceAuthError error_from_add_account_to_cookie_completed_callback_;
@@ -1040,6 +1064,61 @@
       identity_manager()->HasAccountWithRefreshToken(account_info2.account_id));
 }
 
+TEST_F(IdentityManagerTest,
+       CallbackSentOnUpdateToErrorStateOfRefreshTokenForAccount) {
+  AccountInfo primary_account_info =
+      identity_manager()->GetPrimaryAccountInfo();
+  std::string primary_account_id = primary_account_info.account_id;
+  SetRefreshTokenForPrimaryAccount(identity_manager());
+
+  account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2);
+  AccountInfo account_info2 =
+      account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2);
+  std::string account_id2 = account_info2.account_id;
+  SetRefreshTokenForAccount(identity_manager(), account_id2);
+
+  GoogleServiceAuthError account_deleted_error =
+      GoogleServiceAuthError(GoogleServiceAuthError::State::ACCOUNT_DELETED);
+  GoogleServiceAuthError account_disabled_error =
+      GoogleServiceAuthError(GoogleServiceAuthError::State::ACCOUNT_DISABLED);
+  GoogleServiceAuthError transient_error = GoogleServiceAuthError(
+      GoogleServiceAuthError::State::SERVICE_UNAVAILABLE);
+
+  // Set a persistent error for |account_id2| and check that it's reflected.
+  token_service()->UpdateAuthErrorForTesting(account_id2,
+                                             account_deleted_error);
+  EXPECT_EQ(account_id2,
+            identity_manager_observer()
+                ->account_from_error_state_of_refresh_token_updated_callback()
+                .account_id);
+  EXPECT_EQ(account_deleted_error,
+            identity_manager_observer()
+                ->error_from_error_state_of_refresh_token_updated_callback());
+
+  // A transient error should not cause a callback.
+  token_service()->UpdateAuthErrorForTesting(primary_account_id,
+                                             transient_error);
+  EXPECT_EQ(account_id2,
+            identity_manager_observer()
+                ->account_from_error_state_of_refresh_token_updated_callback()
+                .account_id);
+  EXPECT_EQ(account_deleted_error,
+            identity_manager_observer()
+                ->error_from_error_state_of_refresh_token_updated_callback());
+
+  // Set a different persistent error for the primary account and check that
+  // it's reflected.
+  token_service()->UpdateAuthErrorForTesting(primary_account_id,
+                                             account_disabled_error);
+  EXPECT_EQ(primary_account_id,
+            identity_manager_observer()
+                ->account_from_error_state_of_refresh_token_updated_callback()
+                .account_id);
+  EXPECT_EQ(account_disabled_error,
+            identity_manager_observer()
+                ->error_from_error_state_of_refresh_token_updated_callback());
+}
+
 TEST_F(IdentityManagerTest, GetErrorStateOfRefreshTokenForAccount) {
   AccountInfo primary_account_info =
       identity_manager()->GetPrimaryAccountInfo();
@@ -1635,7 +1714,7 @@
   const AccountsInCookieJarInfo& accounts_in_cookie_jar_info =
       identity_manager_observer()->accounts_info_from_cookie_change_callback();
   EXPECT_TRUE(accounts_in_cookie_jar_info.accounts_are_fresh);
-  EXPECT_TRUE(accounts_in_cookie_jar_info.accounts.empty());
+  EXPECT_TRUE(accounts_in_cookie_jar_info.signed_in_accounts.empty());
 }
 
 TEST_F(IdentityManagerTest,
@@ -1652,9 +1731,10 @@
   const AccountsInCookieJarInfo& accounts_in_cookie_jar_info =
       identity_manager_observer()->accounts_info_from_cookie_change_callback();
   EXPECT_TRUE(accounts_in_cookie_jar_info.accounts_are_fresh);
-  ASSERT_EQ(1u, accounts_in_cookie_jar_info.accounts.size());
+  ASSERT_EQ(1u, accounts_in_cookie_jar_info.signed_in_accounts.size());
+  ASSERT_TRUE(accounts_in_cookie_jar_info.signed_out_accounts.empty());
 
-  AccountInfo account_info = accounts_in_cookie_jar_info.accounts[0];
+  AccountInfo account_info = accounts_in_cookie_jar_info.signed_in_accounts[0];
   EXPECT_EQ(account_tracker()->PickAccountIdForAccount(kTestGaiaId, kTestEmail),
             account_info.account_id);
   EXPECT_EQ(kTestGaiaId, account_info.gaia);
@@ -1675,17 +1755,18 @@
   const AccountsInCookieJarInfo& accounts_in_cookie_jar_info =
       identity_manager_observer()->accounts_info_from_cookie_change_callback();
   EXPECT_TRUE(accounts_in_cookie_jar_info.accounts_are_fresh);
-  ASSERT_EQ(2u, accounts_in_cookie_jar_info.accounts.size());
+  ASSERT_EQ(2u, accounts_in_cookie_jar_info.signed_in_accounts.size());
+  ASSERT_TRUE(accounts_in_cookie_jar_info.signed_out_accounts.empty());
 
   // Verify not only that both accounts are present but that they are listed in
   // the expected order as well.
-  AccountInfo account_info1 = accounts_in_cookie_jar_info.accounts[0];
+  AccountInfo account_info1 = accounts_in_cookie_jar_info.signed_in_accounts[0];
   EXPECT_EQ(account_tracker()->PickAccountIdForAccount(kTestGaiaId, kTestEmail),
             account_info1.account_id);
   EXPECT_EQ(kTestGaiaId, account_info1.gaia);
   EXPECT_EQ(kTestEmail, account_info1.email);
 
-  AccountInfo account_info2 = accounts_in_cookie_jar_info.accounts[1];
+  AccountInfo account_info2 = accounts_in_cookie_jar_info.signed_in_accounts[1];
   EXPECT_EQ(
       account_tracker()->PickAccountIdForAccount(kTestGaiaId2, kTestEmail2),
       account_info2.account_id);
@@ -1693,6 +1774,67 @@
   EXPECT_EQ(kTestEmail2, account_info2.email);
 }
 
+TEST_F(IdentityManagerTest, CallbackSentOnUpdateToSignOutAccountsInCookie) {
+  struct SignedOutStatus {
+    int account_1;
+    int account_2;
+  } signed_out_status_set[] = {{0, 0}, {1, 0}, {0, 1}, {1, 1}};
+
+  for (const auto& signed_out_status : signed_out_status_set) {
+    base::RunLoop run_loop;
+    identity_manager_observer()->set_on_accounts_in_cookie_updated_callback(
+        run_loop.QuitClosure());
+
+    gaia_cookie_manager_service()->SetListAccountsResponseWithParams(
+        {{kTestEmail, kTestGaiaId, true /* valid */,
+          signed_out_status.account_1 /* signed_out */, true /* verified */},
+         {kTestEmail2, kTestGaiaId2, true /* valid */,
+          signed_out_status.account_2 /* signed_out */, true /* verified */}});
+
+    gaia_cookie_manager_service()->TriggerListAccounts();
+    run_loop.Run();
+
+    unsigned int accounts_signed_out =
+        signed_out_status.account_1 + signed_out_status.account_2;
+    const AccountsInCookieJarInfo& accounts_in_cookie_jar_info =
+        identity_manager_observer()
+            ->accounts_info_from_cookie_change_callback();
+    EXPECT_TRUE(accounts_in_cookie_jar_info.accounts_are_fresh);
+    ASSERT_EQ(2 - accounts_signed_out,
+              accounts_in_cookie_jar_info.signed_in_accounts.size());
+    ASSERT_EQ(accounts_signed_out,
+              accounts_in_cookie_jar_info.signed_out_accounts.size());
+
+    // Verify not only that both accounts are present but that they are listed
+    // in the expected order as well.
+    //
+    // The two variables below, control the lookup indexes signed in and signed
+    // out accounts list, respectively.
+    int i = 0, j = 0;
+    AccountInfo account_info1 =
+        signed_out_status.account_1
+            ? accounts_in_cookie_jar_info.signed_out_accounts[i++]
+            : accounts_in_cookie_jar_info.signed_in_accounts[j++];
+    if (!signed_out_status.account_1)
+      EXPECT_EQ(
+          account_tracker()->PickAccountIdForAccount(kTestGaiaId, kTestEmail),
+          account_info1.account_id);
+    EXPECT_EQ(kTestGaiaId, account_info1.gaia);
+    EXPECT_EQ(kTestEmail, account_info1.email);
+
+    AccountInfo account_info2 =
+        signed_out_status.account_2
+            ? accounts_in_cookie_jar_info.signed_out_accounts[i++]
+            : accounts_in_cookie_jar_info.signed_in_accounts[j++];
+    if (!signed_out_status.account_2)
+      EXPECT_EQ(
+          account_tracker()->PickAccountIdForAccount(kTestGaiaId2, kTestEmail2),
+          account_info2.account_id);
+    EXPECT_EQ(kTestGaiaId2, account_info2.gaia);
+    EXPECT_EQ(kTestEmail2, account_info2.email);
+  }
+}
+
 TEST_F(IdentityManagerTest,
        CallbackSentOnUpdateToAccountsInCookieWithStaleAccounts) {
   base::RunLoop run_loop;
@@ -1707,7 +1849,8 @@
   const AccountsInCookieJarInfo& accounts_in_cookie_jar_info =
       identity_manager_observer()->accounts_info_from_cookie_change_callback();
   EXPECT_FALSE(accounts_in_cookie_jar_info.accounts_are_fresh);
-  EXPECT_TRUE(accounts_in_cookie_jar_info.accounts.empty());
+  EXPECT_TRUE(accounts_in_cookie_jar_info.signed_in_accounts.empty());
+  EXPECT_TRUE(accounts_in_cookie_jar_info.signed_out_accounts.empty());
 }
 
 TEST_F(IdentityManagerTest, GetAccountsInCookieJarWithNoAccounts) {
@@ -1723,7 +1866,8 @@
   const AccountsInCookieJarInfo& accounts_in_cookie_jar =
       identity_manager()->GetAccountsInCookieJar();
   EXPECT_FALSE(accounts_in_cookie_jar.accounts_are_fresh);
-  EXPECT_TRUE(accounts_in_cookie_jar.accounts.empty());
+  EXPECT_TRUE(accounts_in_cookie_jar.signed_in_accounts.empty());
+  EXPECT_TRUE(accounts_in_cookie_jar.signed_out_accounts.empty());
 
   run_loop.Run();
 
@@ -1733,7 +1877,8 @@
       identity_manager()->GetAccountsInCookieJar();
 
   EXPECT_TRUE(updated_accounts_in_cookie_jar.accounts_are_fresh);
-  EXPECT_TRUE(updated_accounts_in_cookie_jar.accounts.empty());
+  EXPECT_TRUE(updated_accounts_in_cookie_jar.signed_in_accounts.empty());
+  EXPECT_TRUE(updated_accounts_in_cookie_jar.signed_out_accounts.empty());
 }
 
 TEST_F(IdentityManagerTest, GetAccountsInCookieJarWithOneAccount) {
@@ -1750,7 +1895,8 @@
   const AccountsInCookieJarInfo& accounts_in_cookie_jar =
       identity_manager()->GetAccountsInCookieJar();
   EXPECT_FALSE(accounts_in_cookie_jar.accounts_are_fresh);
-  EXPECT_TRUE(accounts_in_cookie_jar.accounts.empty());
+  EXPECT_TRUE(accounts_in_cookie_jar.signed_in_accounts.empty());
+  EXPECT_TRUE(accounts_in_cookie_jar.signed_out_accounts.empty());
 
   run_loop.Run();
 
@@ -1760,9 +1906,11 @@
       identity_manager()->GetAccountsInCookieJar();
 
   EXPECT_TRUE(updated_accounts_in_cookie_jar.accounts_are_fresh);
-  ASSERT_EQ(1u, updated_accounts_in_cookie_jar.accounts.size());
+  ASSERT_EQ(1u, updated_accounts_in_cookie_jar.signed_in_accounts.size());
+  ASSERT_TRUE(updated_accounts_in_cookie_jar.signed_out_accounts.empty());
 
-  AccountInfo account_info = updated_accounts_in_cookie_jar.accounts[0];
+  AccountInfo account_info =
+      updated_accounts_in_cookie_jar.signed_in_accounts[0];
   EXPECT_EQ(account_tracker()->PickAccountIdForAccount(kTestGaiaId, kTestEmail),
             account_info.account_id);
   EXPECT_EQ(kTestGaiaId, account_info.gaia);
@@ -1783,7 +1931,8 @@
   const AccountsInCookieJarInfo& accounts_in_cookie_jar =
       identity_manager()->GetAccountsInCookieJar();
   EXPECT_FALSE(accounts_in_cookie_jar.accounts_are_fresh);
-  EXPECT_TRUE(accounts_in_cookie_jar.accounts.empty());
+  EXPECT_TRUE(accounts_in_cookie_jar.signed_in_accounts.empty());
+  EXPECT_TRUE(accounts_in_cookie_jar.signed_out_accounts.empty());
 
   run_loop.Run();
 
@@ -1793,17 +1942,20 @@
       identity_manager()->GetAccountsInCookieJar();
 
   EXPECT_TRUE(updated_accounts_in_cookie_jar.accounts_are_fresh);
-  ASSERT_EQ(2u, updated_accounts_in_cookie_jar.accounts.size());
+  ASSERT_EQ(2u, updated_accounts_in_cookie_jar.signed_in_accounts.size());
+  ASSERT_TRUE(updated_accounts_in_cookie_jar.signed_out_accounts.empty());
 
   // Verify not only that both accounts are present but that they are listed in
   // the expected order as well.
-  AccountInfo account_info1 = updated_accounts_in_cookie_jar.accounts[0];
+  AccountInfo account_info1 =
+      updated_accounts_in_cookie_jar.signed_in_accounts[0];
   EXPECT_EQ(account_tracker()->PickAccountIdForAccount(kTestGaiaId, kTestEmail),
             account_info1.account_id);
   EXPECT_EQ(kTestGaiaId, account_info1.gaia);
   EXPECT_EQ(kTestEmail, account_info1.email);
 
-  AccountInfo account_info2 = updated_accounts_in_cookie_jar.accounts[1];
+  AccountInfo account_info2 =
+      updated_accounts_in_cookie_jar.signed_in_accounts[1];
   EXPECT_EQ(
       account_tracker()->PickAccountIdForAccount(kTestGaiaId2, kTestEmail2),
       account_info2.account_id);
diff --git a/services/identity/public/cpp/identity_test_environment.cc b/services/identity/public/cpp/identity_test_environment.cc
index 084a34c..6f51c462 100644
--- a/services/identity/public/cpp/identity_test_environment.cc
+++ b/services/identity/public/cpp/identity_test_environment.cc
@@ -278,6 +278,13 @@
   return identity::RemoveRefreshTokenForAccount(identity_manager(), account_id);
 }
 
+void IdentityTestEnvironment::UpdatePersistentErrorOfRefreshTokenForAccount(
+    const std::string& account_id,
+    const GoogleServiceAuthError& auth_error) {
+  return identity::UpdatePersistentErrorOfRefreshTokenForAccount(
+      identity_manager(), account_id, auth_error);
+}
+
 void IdentityTestEnvironment::SetCookieAccounts(
     const std::vector<CookieParams>& cookie_accounts) {
   identity::SetCookieAccounts(gaia_cookie_manager_service_, identity_manager(),
diff --git a/services/identity/public/cpp/identity_test_environment.h b/services/identity/public/cpp/identity_test_environment.h
index ccd4f52..ccc1bf82 100644
--- a/services/identity/public/cpp/identity_test_environment.h
+++ b/services/identity/public/cpp/identity_test_environment.h
@@ -142,6 +142,12 @@
   // NOTE: See disclaimer at top of file re: direct usage.
   void RemoveRefreshTokenForAccount(const std::string& account_id);
 
+  // Updates the persistent auth error set on |account_id| which must be a known
+  // account, i.e., an account with a refresh token.
+  void UpdatePersistentErrorOfRefreshTokenForAccount(
+      const std::string& account_id,
+      const GoogleServiceAuthError& auth_error);
+
   // Puts the given accounts into the Gaia cookie, replacing any previous
   // accounts. Blocks until the accounts have been set.
   void SetCookieAccounts(const std::vector<CookieParams>& cookie_accounts);
diff --git a/services/identity/public/cpp/identity_test_utils.cc b/services/identity/public/cpp/identity_test_utils.cc
index 83127ef7..529f678 100644
--- a/services/identity/public/cpp/identity_test_utils.cc
+++ b/services/identity/public/cpp/identity_test_utils.cc
@@ -194,8 +194,7 @@
   SetInvalidRefreshTokenForAccount(identity_manager, account_id);
 }
 
-void RemoveRefreshTokenForPrimaryAccount(
-    IdentityManager* identity_manager) {
+void RemoveRefreshTokenForPrimaryAccount(IdentityManager* identity_manager) {
   if (!identity_manager->HasPrimaryAccount())
     return;
 
@@ -204,9 +203,8 @@
   RemoveRefreshTokenForAccount(identity_manager, account_id);
 }
 
-AccountInfo MakePrimaryAccountAvailable(
-    IdentityManager* identity_manager,
-    const std::string& email) {
+AccountInfo MakePrimaryAccountAvailable(IdentityManager* identity_manager,
+                                        const std::string& email) {
   AccountInfo account_info = SetPrimaryAccount(identity_manager, email);
   SetRefreshTokenForPrimaryAccount(identity_manager);
   return account_info;
@@ -316,7 +314,7 @@
                        IdentityManager* identity_manager,
                        const std::vector<CookieParams>& cookie_accounts) {
   // Convert |cookie_accounts| to the format FakeGaiaCookieManagerService wants.
-  std::vector<FakeGaiaCookieManagerService::CookieParams> gaia_cookie_accounts;
+  std::vector<signin::CookieParams> gaia_cookie_accounts;
   for (const CookieParams& params : cookie_accounts) {
     gaia_cookie_accounts.push_back({params.email, params.gaia_id,
                                     /*valid=*/true, /*signed_out=*/false,
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index ae6c155..411a2624 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -100,9 +100,8 @@
 }
 
 void CorsURLLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
   if (!network_loader_ || !deferred_redirect_url_) {
     HandleComplete(URLLoaderCompletionStatus(net::ERR_FAILED));
@@ -125,12 +124,9 @@
     return;
   }
 
-  if (to_be_removed_request_headers) {
-    for (const auto& name : *to_be_removed_request_headers)
-      request_.headers.RemoveHeader(name);
-  }
-  if (modified_request_headers)
-    request_.headers.MergeFrom(*modified_request_headers);
+  for (const auto& name : removed_headers)
+    request_.headers.RemoveHeader(name);
+  request_.headers.MergeFrom(modified_headers);
 
   request_.url = redirect_info_.new_url;
   request_.method = redirect_info_.new_method;
@@ -160,8 +156,7 @@
     response_tainting_ = CalculateResponseTainting(
         request_.url, request_.fetch_request_mode, request_.request_initiator,
         fetch_cors_flag_, tainted_, origin_access_list_);
-    network_loader_->FollowRedirect(to_be_removed_request_headers,
-                                    modified_request_headers, new_url);
+    network_loader_->FollowRedirect(removed_headers, modified_headers, new_url);
     return;
   }
   DCHECK_NE(request_.fetch_request_mode, mojom::FetchRequestMode::kNoCors);
diff --git a/services/network/cors/cors_url_loader.h b/services/network/cors/cors_url_loader.h
index 997157f7..cc28bf3 100644
--- a/services/network/cors/cors_url_loader.h
+++ b/services/network/cors/cors_url_loader.h
@@ -58,11 +58,9 @@
   void Start();
 
   // mojom::URLLoader overrides:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int intra_priority_value) override;
diff --git a/services/network/cors/cors_url_loader_unittest.cc b/services/network/cors/cors_url_loader_unittest.cc
index 91c4e43f..7eac462 100644
--- a/services/network/cors/cors_url_loader_unittest.cc
+++ b/services/network/cors/cors_url_loader_unittest.cc
@@ -190,7 +190,10 @@
 
   void FollowRedirect() {
     DCHECK(url_loader_);
-    url_loader_->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+    url_loader_->FollowRedirect({},            // removed_headers
+                                {},            // modified_headers
+                                base::nullopt  // new_url
+    );
   }
 
   const ResourceRequest& GetRequest() const {
diff --git a/services/network/network_service_unittest.cc b/services/network/network_service_unittest.cc
index 4ef51b53..6fd61f4 100644
--- a/services/network/network_service_unittest.cc
+++ b/services/network/network_service_unittest.cc
@@ -758,7 +758,7 @@
   client()->RunUntilRedirectReceived();
   EXPECT_TRUE(client()->has_received_redirect());
   EXPECT_TRUE(!client()->response_head().raw_request_response_info);
-  loader()->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+  loader()->FollowRedirect({}, {}, base::nullopt);
   client()->RunUntilComplete();
   EXPECT_TRUE(!client()->response_head().raw_request_response_info);
 }
@@ -788,7 +788,7 @@
                                  "HTTP/1.1 301 Moved Permanently\r",
                                  base::CompareCase::SENSITIVE));
   }
-  loader()->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+  loader()->FollowRedirect({}, {}, base::nullopt);
   client()->RunUntilComplete();
   {
     scoped_refptr<HttpRawRequestResponseInfo> request_response_info =
@@ -876,12 +876,12 @@
   client()->RunUntilRedirectReceived();  // from a.test to b.test
   EXPECT_TRUE(client()->response_head().raw_request_response_info);
 
-  loader()->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+  loader()->FollowRedirect({}, {}, base::nullopt);
   client()->ClearHasReceivedRedirect();
   client()->RunUntilRedirectReceived();  // from b.test to a.test
   EXPECT_FALSE(client()->response_head().raw_request_response_info);
 
-  loader()->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+  loader()->FollowRedirect({}, {}, base::nullopt);
   client()->RunUntilComplete();  // Done loading a.test
   EXPECT_TRUE(client()->response_head().raw_request_response_info.get());
 
@@ -891,12 +891,12 @@
   client()->RunUntilRedirectReceived();  // from a.test to b.test
   EXPECT_FALSE(client()->response_head().raw_request_response_info);
 
-  loader()->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+  loader()->FollowRedirect({}, {}, base::nullopt);
   client()->ClearHasReceivedRedirect();
   client()->RunUntilRedirectReceived();  // from b.test to a.test
   EXPECT_TRUE(client()->response_head().raw_request_response_info);
 
-  loader()->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+  loader()->FollowRedirect({}, {}, base::nullopt);
   client()->RunUntilComplete();  // Done loading a.test
   EXPECT_FALSE(client()->response_head().raw_request_response_info.get());
 }
diff --git a/services/network/public/cpp/simple_url_loader.cc b/services/network/public/cpp/simple_url_loader.cc
index 04bc90e..0b4f4b9 100644
--- a/services/network/public/cpp/simple_url_loader.cc
+++ b/services/network/public/cpp/simple_url_loader.cc
@@ -1604,12 +1604,12 @@
     return;
   }
 
-  std::vector<std::string> to_be_removed_headers;
+  std::vector<std::string> removed_headers;
   for (auto callback : on_redirect_callback_) {
     if (callback) {
       base::WeakPtr<SimpleURLLoaderImpl> weak_this =
           weak_ptr_factory_.GetWeakPtr();
-      callback.Run(redirect_info, response_head, &to_be_removed_headers);
+      callback.Run(redirect_info, response_head, &removed_headers);
       // If deleted by the callback, bail now.
       if (!weak_this)
         return;
@@ -1617,12 +1617,8 @@
   }
 
   final_url_ = redirect_info.new_url;
-  if (to_be_removed_headers.empty()) {
-    url_loader_->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
-  } else {
-    url_loader_->FollowRedirect(to_be_removed_headers, base::nullopt,
-                                base::nullopt);
-  }
+  url_loader_->FollowRedirect(removed_headers, {} /* modified_headers */,
+                              {} /* new_url */);
 }
 
 void SimpleURLLoaderImpl::OnReceiveCachedMetadata(
diff --git a/services/network/public/cpp/simple_url_loader.h b/services/network/public/cpp/simple_url_loader.h
index dd9c8e0..f81788d 100644
--- a/services/network/public/cpp/simple_url_loader.h
+++ b/services/network/public/cpp/simple_url_loader.h
@@ -108,12 +108,12 @@
 
   // Callback used when a redirect is being followed. It is safe to delete the
   // SimpleURLLoader during the callback.
-  // |to_be_removed_headers| is used to set variations headers that need to be
+  // |removed_headers| is used to set variations headers that need to be
   // removed for requests when a redirect to a non-Google URL occurs.
-  using OnRedirectCallback = base::RepeatingCallback<void(
-      const net::RedirectInfo& redirect_info,
-      const ResourceResponseHead& response_head,
-      std::vector<std::string>* to_be_removed_headers)>;
+  using OnRedirectCallback =
+      base::RepeatingCallback<void(const net::RedirectInfo& redirect_info,
+                                   const ResourceResponseHead& response_head,
+                                   std::vector<std::string>* removed_headers)>;
 
   // Callback used when a response is received. It is safe to delete the
   // SimpleURLLoader during the callback.
diff --git a/services/network/public/cpp/simple_url_loader_unittest.cc b/services/network/public/cpp/simple_url_loader_unittest.cc
index f2b5368c..f7780cc 100644
--- a/services/network/public/cpp/simple_url_loader_unittest.cc
+++ b/services/network/public/cpp/simple_url_loader_unittest.cc
@@ -1925,11 +1925,9 @@
   ~MockURLLoader() override {}
 
   // network::mojom::URLLoader implementation:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override {}
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override {}
   void ProceedWithResponse() override {}
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override {
diff --git a/services/network/public/mojom/url_loader.mojom b/services/network/public/mojom/url_loader.mojom
index e55427a..2e6c20f8 100644
--- a/services/network/public/mojom/url_loader.mojom
+++ b/services/network/public/mojom/url_loader.mojom
@@ -43,19 +43,18 @@
   // description, to notify the service side.
   const uint32 kClientDisconnectReason = 1;
 
-  // If the associated request has |auto_follow_redirects| set to false,
-  // then upon receiving an URLResponse with a non-NULL |redirect_url| field,
+  // If the associated request has |auto_follow_redirects| set to false, then
+  // upon receiving an URLResponse with a non-NULL |redirect_url| field,
   // |FollowRedirect| may be called to load the URL indicated by the redirect.
-  // |to_be_removed_request_headers| can be used to remove existing headers for
-  // the redirect. This parameter is before |modified_request_headers| since
-  // removing headers is applied first in the URLLoader::FollowRedirect().
-  // |modified_request_headers| can be used to add or override existing headers
-  // for the redirect. If |new_url| is specified, then the request will be made
-  // to it instead of the redirected URL. Note: it has to be in the same origin
-  // as the redirected URL, and this is only supported when the network service
-  // is enabled.
-  FollowRedirect(array<string>? to_be_removed_request_headers,
-                 network.mojom.HttpRequestHeaders? modified_request_headers,
+  // |removed_headers| can be used to remove existing headers for the redirect.
+  // This parameter is before |modified_headers| since removing headers is
+  // applied first in the URLLoader::FollowRedirect().  |modified_headers| can
+  // be used to add or override existing headers for the redirect. If |new_url|
+  // is specified, then the request will be made to it instead of the redirected
+  // URL. Note: it has to be in the same origin as the redirected URL, and this
+  // is only supported when the network service is enabled.
+  FollowRedirect(array<string> removed_headers,
+                 network.mojom.HttpRequestHeaders modified_headers,
                  url.mojom.Url? new_url);
 
   // Resumes loading the response body if the URLLoader paused the request upon
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index db931610..a4159d9 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -556,10 +556,9 @@
 // static
 const void* const URLLoader::kUserDataKey = &URLLoader::kUserDataKey;
 
-void URLLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>& removed_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_headers,
-    const base::Optional<GURL>& new_url) {
+void URLLoader::FollowRedirect(const std::vector<std::string>& removed_headers,
+                               const net::HttpRequestHeaders& modified_headers,
+                               const base::Optional<GURL>& new_url) {
   if (!url_request_) {
     NotifyCompleted(net::ERR_UNEXPECTED);
     // |this| may have been deleted.
diff --git a/services/network/url_loader.h b/services/network/url_loader.h
index 1776e32..277d8da 100644
--- a/services/network/url_loader.h
+++ b/services/network/url_loader.h
@@ -72,11 +72,9 @@
   ~URLLoader() override;
 
   // mojom::URLLoader implementation:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override;
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override;
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index 0112c57..0e5c319 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -443,7 +443,7 @@
 
     if (expect_redirect_) {
       client_.RunUntilRedirectReceived();
-      loader->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+      loader->FollowRedirect({}, {}, base::nullopt);
     }
 
     if (body) {
@@ -1720,7 +1720,7 @@
   net::HttpRequestHeaders redirect_headers;
   redirect_headers.SetHeader("Header2", "");
   redirect_headers.SetHeader("Header3", "Value3");
-  loader->FollowRedirect(base::nullopt, redirect_headers, base::nullopt);
+  loader->FollowRedirect({}, redirect_headers, base::nullopt);
 
   client()->RunUntilComplete();
   delete_run_loop.Run();
@@ -1761,9 +1761,8 @@
   EXPECT_EQ("Value2", request_headers1.find("Header2")->second);
 
   // Remove Header1.
-  std::vector<std::string> to_be_removed_request_headers = {"Header1"};
-  loader->FollowRedirect(to_be_removed_request_headers, base::nullopt,
-                         base::nullopt);
+  std::vector<std::string> removed_headers = {"Header1"};
+  loader->FollowRedirect(removed_headers, {}, base::nullopt);
 
   client()->RunUntilComplete();
   delete_run_loop.Run();
@@ -1803,11 +1802,10 @@
   EXPECT_EQ("Value2", request_headers1.find("Header2")->second);
 
   // Remove Header1 and add it back using a different value.
-  std::vector<std::string> to_be_removed_request_headers = {"Header1"};
-  net::HttpRequestHeaders redirect_headers;
-  redirect_headers.SetHeader("Header1", "NewValue1");
-  loader->FollowRedirect(to_be_removed_request_headers, redirect_headers,
-                         base::nullopt);
+  std::vector<std::string> removed_headers = {"Header1"};
+  net::HttpRequestHeaders modified_headers;
+  modified_headers.SetHeader("Header1", "NewValue1");
+  loader->FollowRedirect(removed_headers, modified_headers, base::nullopt);
 
   client()->RunUntilComplete();
   delete_run_loop.Run();
@@ -2705,9 +2703,8 @@
 
   client()->RunUntilRedirectReceived();
 
-  url_loader->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
-  EXPECT_DCHECK_DEATH(
-      url_loader->FollowRedirect(base::nullopt, base::nullopt, base::nullopt));
+  url_loader->FollowRedirect({}, {}, base::nullopt);
+  EXPECT_DCHECK_DEATH(url_loader->FollowRedirect({}, {}, base::nullopt));
 
   client()->RunUntilComplete();
   delete_run_loop.Run();
diff --git a/storage/browser/blob/blob_url_loader.cc b/storage/browser/blob/blob_url_loader.cc
index 21350d8..31ad67656 100644
--- a/storage/browser/blob/blob_url_loader.cc
+++ b/storage/browser/blob/blob_url_loader.cc
@@ -97,9 +97,8 @@
 }
 
 void BlobURLLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+    const std::vector<std::string>& removed_headers,
+    const net::HttpRequestHeaders& modified_headers,
     const base::Optional<GURL>& new_url) {
   NOTREACHED();
 }
diff --git a/storage/browser/blob/blob_url_loader.h b/storage/browser/blob/blob_url_loader.h
index 907fa124..0bc8a30 100644
--- a/storage/browser/blob/blob_url_loader.h
+++ b/storage/browser/blob/blob_url_loader.h
@@ -40,11 +40,9 @@
   void Start(const network::ResourceRequest& request);
 
   // network::mojom::URLLoader implementation:
-  void FollowRedirect(
-      const base::Optional<std::vector<std::string>>&
-          to_be_removed_request_headers,
-      const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
-      const base::Optional<GURL>& new_url) override;
+  void FollowRedirect(const std::vector<std::string>& removed_headers,
+                      const net::HttpRequestHeaders& modified_request_headers,
+                      const base::Optional<GURL>& new_url) override;
   void ProceedWithResponse() override {}
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override {}
diff --git a/styleguide/web/es.md b/styleguide/web/es.md
index d94bd40..b0dcd23a 100644
--- a/styleguide/web/es.md
+++ b/styleguide/web/es.md
@@ -462,6 +462,55 @@
 
 ---
 
+### Spread Operators
+
+Spreading the elements from an iterable collection into individual literals as
+function parameters.
+
+This only applies to arrays and not objects.
+
+**Usage Example:**
+
+```js
+// Spreading an Array
+var params = ['hello', true, 7];
+var other = [1, 2, ...params];  // [1, 2, 'hello', true, 7]
+
+// Spreading a String
+var str = 'foo';
+var chars = [...str];  // ['f', 'o', 'o']
+```
+
+**Documentation:** [link](http://www.ecma-international.org/ecma-262/6.0/#sec-argument-lists-runtime-semantics-argumentlistevaluation)
+
+**Discussion Notes / Link to Thread:** [link](https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/LqP4AniIs8c)
+
+---
+
+### Rest Parameters
+
+Aggregation of function arguments into one Array variable.
+
+This only applies to arrays and function parameters, and not objects.
+
+**Usage Example:**
+
+```js
+function usesRestParams(a, b, ...theRest) {
+  console.log(a);  // 'a'
+  console.log(b);  // 'b'
+  console.log(theRest);  // [1, 2, 3]
+}
+
+usesRestParams('a', 'b', 1, 2, 3);
+```
+
+**Documentation:** [link](http://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions)
+
+**Discussion Notes / Link to Thread:** [link](https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/LqP4AniIs8c)
+
+---
+
 ## Banned Features
 
 The following features are banned for Chromium development.
@@ -529,51 +578,6 @@
 
 ---
 
-### Rest Parameters
-
-Aggregation of function arguments into one Array variable.
-
-**Usage Example:**
-
-```js
-function usesRestParams(a, b, ...theRest) {
-  console.log(a);  // 'a'
-  console.log(b);  // 'b'
-  console.log(theRest);  // [1, 2, 3]
-}
-
-usesRestParams('a', 'b', 1, 2, 3);
-```
-
-**Documentation:** [link](https://tc39.github.io/ecma262/#sec-function-definitions)
-
-**Discussion Notes / Link to Thread:**
-
----
-
-### Spread Operators
-
-Spreading the elements from an iterable collection into individual literals as
-function parameters.
-
-**Usage Example:**
-
-```js
-// Spreading an Array
-const params = ['hello', true, 7];
-const other = [1, 2, ...params];  // [1, 2, 'hello', true, 7]
-
-// Spreading a String
-const str = 'foo';
-const chars = [...str];  // ['f', 'o', 'o']
-```
-
-**Documentation:** [link](https://tc39.github.io/ecma262/#sec-argument-lists-runtime-semantics-argumentlistevaluation)
-
-**Discussion Notes / Link to Thread:**
-
----
-
 ### Object Literal Extensions
 
 Convenient new ways for object property definition.
diff --git a/third_party/arcore-android-sdk/BUILD.gn b/third_party/arcore-android-sdk/BUILD.gn
index c6b23c1..9f7d9e4 100644
--- a/third_party/arcore-android-sdk/BUILD.gn
+++ b/third_party/arcore-android-sdk/BUILD.gn
@@ -4,12 +4,6 @@
 
 import("//build/config/android/rules.gni")
 
-java_prebuilt("libdynamite_client_java") {
-  supports_android = true
-  proguard_configs = [ "proguard-arcore.txt" ]
-  jar_path = "libarcore_client_c.jar"
-}
-
 config("libarcore_config") {
   include_dirs = [ "src/libraries/include/" ]
 }
diff --git a/third_party/arcore-android-sdk/README.chromium b/third_party/arcore-android-sdk/README.chromium
index 1d04387..86ba41a 100644
--- a/third_party/arcore-android-sdk/README.chromium
+++ b/third_party/arcore-android-sdk/README.chromium
@@ -1,8 +1,7 @@
 Name: ARCore SDK
 Short Name: arcore
 URL: https://github.com/google-ar/arcore-android-sdk
-Version: 1.1
-Date: 19 March 2018
+Version: 1.5
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
@@ -12,11 +11,7 @@
 devices.
 
 Local Modifications:
-To address binary size concerns, we are using a minimal shim produced for
-Chromium that is not publicly distributed elsewhere. We have also stripped the
-.so's to minimize their size.
-
-Also, added BUILD.gn for compilation in chrome.
+Added BUILD.gn for compilation in chrome.
 
 Added the test-apks/ subdirectory for storing production versions of AR APKs,
 namely ArCore, for testing.
@@ -29,6 +24,8 @@
  * https://github.com/google-ar/arcore-unity-sdk/blob/master/LICENSE
 
 Changes:
+2018-12-11 - Upgrade ARCore to v1.5. Remove checked in .so files - we now
+             extract them from ARCore's .aar file at build time.
 2018-12-11 - Upgrade test-apks/arcore_current.apk to v1.6.
 2018-09-14 - Upgrade test-apks/arcore_current.apk to v1.4.
 2018-08-10 - First, removed arcore shim copy target from BUILD.gn since it is no
diff --git a/third_party/arcore-android-sdk/libarcore_client_c.jar b/third_party/arcore-android-sdk/libarcore_client_c.jar
deleted file mode 100644
index 335fe92..0000000
--- a/third_party/arcore-android-sdk/libarcore_client_c.jar
+++ /dev/null
Binary files differ
diff --git a/third_party/arcore-android-sdk/libarcore_dummy.so b/third_party/arcore-android-sdk/libarcore_dummy.so
deleted file mode 100644
index e69de29..0000000
--- a/third_party/arcore-android-sdk/libarcore_dummy.so
+++ /dev/null
diff --git a/third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so b/third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so
deleted file mode 100755
index ce3ab2df..0000000
--- a/third_party/arcore-android-sdk/libraries/android_arm/libarcore_sdk_c_minimal.so
+++ /dev/null
Binary files differ
diff --git a/third_party/arcore-android-sdk/libraries/android_arm64/libarcore_sdk_c_minimal.so b/third_party/arcore-android-sdk/libraries/android_arm64/libarcore_sdk_c_minimal.so
deleted file mode 100755
index cfd9654f..0000000
--- a/third_party/arcore-android-sdk/libraries/android_arm64/libarcore_sdk_c_minimal.so
+++ /dev/null
Binary files differ
diff --git a/third_party/arcore-android-sdk/proguard-arcore.txt b/third_party/arcore-android-sdk/proguard-arcore.txt
deleted file mode 100644
index b1c85042..0000000
--- a/third_party/arcore-android-sdk/proguard-arcore.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-# Keep ARCore public-facing classes
--keepparameternames
--renamesourcefileattribute SourceFile
-
-# These are part of the Java <-> native interfaces for ARCore.
--keepclasseswithmembernames,includedescriptorclasses class com.google.ar.** {
-    native <methods>;
-}
-
--keep public class com.google.ar.core.** {*;}
-
--keep class com.google.ar.core.annotations.UsedByNative
--keep @com.google.ar.core.annotations.UsedByNative class *
--keepclassmembers class * {
-    @com.google.ar.core.annotations.UsedByNative *;
-}
-
--keep class com.google.ar.core.annotations.UsedByReflection
--keep @com.google.ar.core.annotations.UsedByReflection class *
--keepclassmembers class * {
-    @com.google.ar.core.annotations.UsedByReflection *;
-}
-# Keep Dynamite classes
-
-# .aidl file will be proguarded, we should keep all Aidls.
--keep class com.google.vr.dynamite.client.IObjectWrapper { *; }
--keep class com.google.vr.dynamite.client.ILoadedInstanceCreator { *; }
--keep class com.google.vr.dynamite.client.INativeLibraryLoader { *; }
-
-# Keep annotation files and the file got annotated.
--keep class com.google.vr.dynamite.client.UsedByNative
--keep @com.google.vr.dynamite.client.UsedByNative class *
--keepclassmembers class * {
-    @com.google.vr.dynamite.client.UsedByNative *;
-}
-
--keep class com.google.vr.dynamite.client.UsedByReflection
--keep @com.google.vr.dynamite.client.UsedByReflection class *
--keepclassmembers class * {
-    @com.google.vr.dynamite.client.UsedByReflection *;
-}
diff --git a/third_party/blink/public/common/manifest/manifest.h b/third_party/blink/public/common/manifest/manifest.h
index 01f78a8..8adecc5 100644
--- a/third_party/blink/public/common/manifest/manifest.h
+++ b/third_party/blink/public/common/manifest/manifest.h
@@ -56,9 +56,8 @@
     // The special value "any" is represented by gfx::Size(0, 0).
     std::vector<gfx::Size> sizes;
 
-    // Empty if the field was not present or not of type "string". Defaults to
-    // a vector with a single value, IconPurpose::ANY, for all other parsing
-    // exceptions.
+    // Never empty. Defaults to a vector with a single value, IconPurpose::ANY,
+    // if not explicitly specified in the manifest.
     std::vector<Purpose> purpose;
   };
 
diff --git a/third_party/blink/public/mojom/manifest/manifest.mojom b/third_party/blink/public/mojom/manifest/manifest.mojom
index 4818501..0e746a6 100644
--- a/third_party/blink/public/mojom/manifest/manifest.mojom
+++ b/third_party/blink/public/mojom/manifest/manifest.mojom
@@ -78,8 +78,8 @@
   // The special value "any" is represented by gfx::Size(0, 0).
   array<gfx.mojom.Size> sizes;
 
-  // Defaults to a vector with a single value, Purpose::ANY, for all other
-  // parsing exceptions.
+  // Never empty. Defaults to a vector with a single value, IconPurpose::ANY,
+  // if not explicitly specified in the manifest.
   array<Purpose> purpose;
 };
 
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom
index eaa37cb..af761ca 100644
--- a/third_party/blink/public/platform/web_feature.mojom
+++ b/third_party/blink/public/platform/web_feature.mojom
@@ -2160,6 +2160,10 @@
   kHistoryLength = 2719,
   kFeaturePolicyReportOnlyHeader = 2720,
   kV8PaymentRequest_HasEnrolledInstrument_Method = 2721,
+  kTrustedTypesEnabled = 2722,
+  kTrustedTypesCreatePolicy = 2723,
+  kTrustedTypesDefaultPolicyUsed = 2724,
+  kTrustedTypesAssignmentError = 2725,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/web/web_remote_frame_client.h b/third_party/blink/public/web/web_remote_frame_client.h
index de85c47..793b2c2 100644
--- a/third_party/blink/public/web/web_remote_frame_client.h
+++ b/third_party/blink/public/web/web_remote_frame_client.h
@@ -39,6 +39,7 @@
   // A remote frame was asked to start a navigation.
   virtual void Navigate(const WebURLRequest& request,
                         bool should_replace_current_entry,
+                        bool is_opener_navigation,
                         mojo::ScopedMessagePipeHandle blob_url_token) {}
 
   virtual void FrameRectsChanged(const WebRect& local_frame_rect,
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 5560fc9..91bce17 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -9670,6 +9670,7 @@
   // frame_test_helpers::TestWebRemoteFrameClient:
   void Navigate(const WebURLRequest& request,
                 bool should_replace_current_entry,
+                bool is_opener_navigation,
                 mojo::ScopedMessagePipeHandle) override {
     last_request_ = request;
   }
@@ -9714,20 +9715,20 @@
   LocalDOMWindow* main_window =
       ToWebLocalFrameImpl(MainFrame())->GetFrame()->DomWindow();
 
-  KURL destination = ToKURL("data:text/html:destination");
+  String destination = "data:text/html:destination";
   NonThrowableExceptionState exception_state;
   main_window->open(
       USVStringOrTrustedURL::FromTrustedURL(TrustedURL::Create(destination)),
       "frame1", "", main_window, main_window, exception_state);
   ASSERT_FALSE(remote_client.LastRequest().IsNull());
-  EXPECT_EQ(remote_client.LastRequest().Url(), WebURL(destination));
+  EXPECT_EQ(remote_client.LastRequest().Url(), WebURL(KURL(destination)));
 
   // Pointing a named frame to an empty URL should just return a reference to
   // the frame's window without navigating it.
   DOMWindow* result = main_window->open(
-      USVStringOrTrustedURL::FromTrustedURL(TrustedURL::Create(ToKURL(""))),
-      "frame1", "", main_window, main_window, exception_state);
-  EXPECT_EQ(remote_client.LastRequest().Url(), WebURL(destination));
+      USVStringOrTrustedURL::FromTrustedURL(TrustedURL::Create("")), "frame1",
+      "", main_window, main_window, exception_state);
+  EXPECT_EQ(remote_client.LastRequest().Url(), WebURL(KURL(destination)));
   EXPECT_EQ(result, WebFrame::ToCoreFrame(*remote_frame)->DomWindow());
 
   Reset();
diff --git a/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc b/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
index eed388bf..eefe4b8 100644
--- a/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
@@ -297,8 +297,10 @@
       ToWebLocalFrameImpl(Parent()->ToWebLocalFrame());
   HTMLFrameOwnerElement* owner_element =
       ToHTMLFrameOwnerElement(frame_->Owner());
+  DCHECK(owner_element);
   DOMWindowPerformance::performance(*parent_frame->GetFrame()->DomWindow())
-      ->AddResourceTiming(info, owner_element->localName());
+      ->AddResourceTiming(info, owner_element->localName(),
+                          owner_element->GetDocument().IsSecureContext());
 }
 
 void WebRemoteFrameImpl::DispatchLoadEventForFrameOwner() {
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index d4660b7..29cf8eb 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -487,7 +487,7 @@
   {
     ContextMenuAllowedScope scope;
     target_local_frame->GetEventHandler().SendContextMenuEvent(
-        transformed_event, nullptr);
+        transformed_event);
   }
   // Actually showing the context menu is handled by the ContextMenuController
   // implementation...
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc
index 1db7ea1..a6ac0dd 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -91,9 +91,12 @@
   FrameLoader::UpgradeInsecureRequest(frame_request.GetResourceRequest(),
                                       frame_request.OriginDocument());
 
+  Document* document = frame_request.OriginDocument();
+  bool is_opener_navigation = document && document->GetFrame() &&
+                              document->GetFrame()->Client()->Opener() == this;
   Client()->Navigate(frame_request.GetResourceRequest(),
                      frame_load_type == WebFrameLoadType::kReplaceCurrentItem,
-                     frame_request.GetBlobURLToken());
+                     is_opener_navigation, frame_request.GetBlobURLToken());
 }
 
 void RemoteFrame::DetachImpl(FrameDetachType type) {
diff --git a/third_party/blink/renderer/core/frame/remote_frame_client.h b/third_party/blink/renderer/core/frame/remote_frame_client.h
index faf6c60..f22a8176 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_client.h
+++ b/third_party/blink/renderer/core/frame/remote_frame_client.h
@@ -30,6 +30,7 @@
 
   virtual void Navigate(const ResourceRequest&,
                         bool should_replace_current_entry,
+                        bool is_opener_navigation,
                         mojom::blink::BlobURLTokenPtr) = 0;
   unsigned BackForwardLength() override = 0;
 
diff --git a/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc b/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
index 3a840c69..fc52f11 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame_client_impl.cc
@@ -111,11 +111,12 @@
 void RemoteFrameClientImpl::Navigate(
     const ResourceRequest& request,
     bool should_replace_current_entry,
+    bool is_opener_navigation,
     mojom::blink::BlobURLTokenPtr blob_url_token) {
   if (web_frame_->Client()) {
-    web_frame_->Client()->Navigate(WrappedResourceRequest(request),
-                                   should_replace_current_entry,
-                                   blob_url_token.PassInterface().PassHandle());
+    web_frame_->Client()->Navigate(
+        WrappedResourceRequest(request), should_replace_current_entry,
+        is_opener_navigation, blob_url_token.PassInterface().PassHandle());
   }
 }
 
diff --git a/third_party/blink/renderer/core/frame/remote_frame_client_impl.h b/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
index bfdd480..aa33cc9 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
+++ b/third_party/blink/renderer/core/frame/remote_frame_client_impl.h
@@ -37,6 +37,7 @@
   // RemoteFrameClient overrides:
   void Navigate(const ResourceRequest&,
                 bool should_replace_current_entry,
+                bool is_opener_navigation,
                 mojom::blink::BlobURLTokenPtr) override;
   unsigned BackForwardLength() override;
   void CheckCompleted() override;
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.cc b/third_party/blink/renderer/core/frame/visual_viewport.cc
index e3c41b6..a9cfb41 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport.cc
+++ b/third_party/blink/renderer/core/frame/visual_viewport.cc
@@ -224,8 +224,7 @@
     overlay_scrollbar_horizontal_->SetLayerState(
         PropertyTreeState(transform_parent, context.current.clip,
                           horizontal_scrollbar_effect_node_.get()),
-        IntPoint(overlay_scrollbar_horizontal_->GetPosition().x(),
-                 overlay_scrollbar_horizontal_->GetPosition().y()));
+        ScrollbarOffset(ScrollbarOrientation::kHorizontalScrollbar));
   }
 
   if (overlay_scrollbar_vertical_) {
@@ -245,8 +244,7 @@
     overlay_scrollbar_vertical_->SetLayerState(
         PropertyTreeState(transform_parent, context.current.clip,
                           vertical_scrollbar_effect_node_.get()),
-        IntPoint(overlay_scrollbar_vertical_->GetPosition().x(),
-                 overlay_scrollbar_vertical_->GetPosition().y()));
+        ScrollbarOffset(ScrollbarOrientation::kVerticalScrollbar));
   }
 }
 
@@ -639,6 +637,32 @@
     frame->View()->VisualViewportScrollbarsChanged();
 }
 
+int VisualViewport::ScrollbarThickness() const {
+  ScrollbarThemeOverlay& theme = ScrollbarThemeOverlay::MobileTheme();
+  int thickness = theme.ScrollbarThickness(kRegularScrollbar);
+  return clampTo<int>(std::floor(
+      GetPage().GetChromeClient().WindowToViewportScalar(thickness)));
+}
+
+IntSize VisualViewport::ScrollbarSize(ScrollbarOrientation orientation) const {
+  if (orientation == kHorizontalScrollbar) {
+    int viewport_width = inner_viewport_container_layer_->Size().width();
+    return IntSize(viewport_width - ScrollbarThickness(), ScrollbarThickness());
+  }
+  int viewport_height = inner_viewport_container_layer_->Size().height();
+  return IntSize(ScrollbarThickness(), viewport_height - ScrollbarThickness());
+}
+
+IntPoint VisualViewport::ScrollbarOffset(
+    ScrollbarOrientation orientation) const {
+  if (orientation == kHorizontalScrollbar) {
+    int viewport_height = inner_viewport_container_layer_->Size().height();
+    return IntPoint(0, viewport_height - ScrollbarThickness());
+  }
+  int viewport_width = inner_viewport_container_layer_->Size().width();
+  return IntPoint(viewport_width - ScrollbarThickness(), 0);
+}
+
 void VisualViewport::SetupScrollbar(ScrollbarOrientation orientation) {
   bool is_horizontal = orientation == kHorizontalScrollbar;
   GraphicsLayer* scrollbar_graphics_layer =
@@ -647,26 +671,20 @@
   std::unique_ptr<ScrollingCoordinator::ScrollbarLayerGroup>&
       scrollbar_layer_group = is_horizontal ? scrollbar_layer_group_horizontal_
                                             : scrollbar_layer_group_vertical_;
-  if (!scrollbar_graphics_layer->Parent()) {
+  if (!scrollbar_graphics_layer->Parent())
     inner_viewport_container_layer_->AddChild(scrollbar_graphics_layer);
-    scrollbar_graphics_layer->SetLayerState(
-        PropertyTreeState(PropertyTreeState::Root()), IntPoint());
-  }
-  ScrollbarThemeOverlay& theme = ScrollbarThemeOverlay::MobileTheme();
-  int thumb_thickness = clampTo<int>(
-      std::floor(GetPage().GetChromeClient().WindowToViewportScalar(
-          theme.ThumbThickness())));
-  int scrollbar_thickness = clampTo<int>(
-      std::floor(GetPage().GetChromeClient().WindowToViewportScalar(
-          theme.ScrollbarThickness(kRegularScrollbar))));
-  int scrollbar_margin = clampTo<int>(
-      std::floor(GetPage().GetChromeClient().WindowToViewportScalar(
-          theme.ScrollbarMargin())));
 
   if (!scrollbar_layer_group) {
     ScrollingCoordinator* coordinator = GetPage().GetScrollingCoordinator();
     DCHECK(coordinator);
 
+    ScrollbarThemeOverlay& theme = ScrollbarThemeOverlay::MobileTheme();
+    int thumb_thickness = clampTo<int>(
+        std::floor(GetPage().GetChromeClient().WindowToViewportScalar(
+            theme.ThumbThickness())));
+    int scrollbar_margin = clampTo<int>(
+        std::floor(GetPage().GetChromeClient().WindowToViewportScalar(
+            theme.ScrollbarMargin())));
     scrollbar_layer_group = coordinator->CreateSolidColorScrollbarLayer(
         orientation, thumb_thickness, scrollbar_margin, false,
         GetScrollbarElementId(orientation));
@@ -682,26 +700,18 @@
         inner_viewport_scroll_layer_->CcLayer()->element_id());
   }
 
-  int x_position = is_horizontal
-                       ? 0
-                       : inner_viewport_container_layer_->Size().width() -
-                             scrollbar_thickness;
-  int y_position = is_horizontal
-                       ? inner_viewport_container_layer_->Size().height() -
-                             scrollbar_thickness
-                       : 0;
-  int width = is_horizontal ? inner_viewport_container_layer_->Size().width() -
-                                  scrollbar_thickness
-                            : scrollbar_thickness;
-  int height = is_horizontal
-                   ? scrollbar_thickness
-                   : inner_viewport_container_layer_->Size().height() -
-                         scrollbar_thickness;
+  // Use the GraphicsLayer to position the scrollbars. This is not needed with
+  // BlinkGenPropertyTrees because the cc::Layer's offset_to_transform_parent is
+  // set directly with GraphicsLayer::SetLayerState instead of being calculated
+  // from the cc::Layer's position.
+  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+    const auto& position = ScrollbarOffset(orientation);
+    scrollbar_graphics_layer->SetPosition(FloatPoint(position));
+  }
 
-  // Use the GraphicsLayer to position the scrollbars.
-  scrollbar_graphics_layer->SetPosition(FloatPoint(x_position, y_position));
-  scrollbar_graphics_layer->SetSize(gfx::Size(width, height));
-  scrollbar_graphics_layer->SetContentsRect(IntRect(0, 0, width, height));
+  const auto& size = ScrollbarSize(orientation);
+  scrollbar_graphics_layer->SetSize(gfx::Size(size));
+  scrollbar_graphics_layer->SetContentsRect(IntRect(IntPoint(), size));
 
   needs_paint_property_update_ = true;
 }
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.h b/third_party/blink/renderer/core/frame/visual_viewport.h
index a3f0892..0b03bd0 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport.h
+++ b/third_party/blink/renderer/core/frame/visual_viewport.h
@@ -301,6 +301,10 @@
   const ScrollableArea* GetScrollableAreaForTesting(
       const GraphicsLayer*) const override;
 
+  int ScrollbarThickness() const;
+  IntSize ScrollbarSize(ScrollbarOrientation) const;
+  IntPoint ScrollbarOffset(ScrollbarOrientation) const;
+
   void SetupScrollbar(ScrollbarOrientation);
 
   void NotifyRootFrameViewport() const;
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
index ded7dd5f..53fd46d 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -755,7 +755,7 @@
   {
     ContextMenuAllowedScope scope;
     target_local_frame->GetEventHandler().SendContextMenuEvent(
-        transformed_event, nullptr);
+        transformed_event);
   }
   // Actually showing the context menu is handled by the ContextMenuClient
   // implementation...
diff --git a/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc b/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
index 5ae900a..eb64c4c 100644
--- a/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
+++ b/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
@@ -281,7 +281,7 @@
 void SliderThumbElement::DetachLayoutTree(const AttachContext& context) {
   if (in_drag_mode_) {
     if (LocalFrame* frame = GetDocument().GetFrame())
-      frame->GetEventHandler().SetCapturingMouseEventsNode(nullptr);
+      frame->GetEventHandler().SetCapturingMouseEventsElement(nullptr);
   }
   HTMLDivElement::DetachLayoutTree(context);
 }
diff --git a/third_party/blink/renderer/core/html/forms/spin_button_element.cc b/third_party/blink/renderer/core/html/forms/spin_button_element.cc
index f2f78867..8406889 100644
--- a/third_party/blink/renderer/core/html/forms/spin_button_element.cc
+++ b/third_party/blink/renderer/core/html/forms/spin_button_element.cc
@@ -120,7 +120,7 @@
     if (box->PixelSnappedBorderBoxRect().Contains(local)) {
       if (!capturing_) {
         if (LocalFrame* frame = GetDocument().GetFrame()) {
-          frame->GetEventHandler().SetCapturingMouseEventsNode(this);
+          frame->GetEventHandler().SetCapturingMouseEventsElement(this);
           capturing_ = true;
           if (Page* page = GetDocument().GetPage())
             page->GetChromeClient().RegisterPopupOpeningObserver(this);
@@ -191,7 +191,7 @@
   if (!capturing_)
     return;
   if (LocalFrame* frame = GetDocument().GetFrame()) {
-    frame->GetEventHandler().SetCapturingMouseEventsNode(nullptr);
+    frame->GetEventHandler().SetCapturingMouseEventsElement(nullptr);
     capturing_ = false;
     if (Page* page = GetDocument().GetPage())
       page->GetChromeClient().UnregisterPopupOpeningObserver(this);
diff --git a/third_party/blink/renderer/core/html/html_link_element.cc b/third_party/blink/renderer/core/html/html_link_element.cc
index 374c5fa5..6510c63 100644
--- a/third_party/blink/renderer/core/html/html_link_element.cc
+++ b/third_party/blink/renderer/core/html/html_link_element.cc
@@ -172,7 +172,7 @@
 
   if (!link_) {
     if (rel_attribute_.IsImport() &&
-        RuntimeEnabledFeatures::HTMLImportsEnabled()) {
+        origin_trials::HTMLImportsEnabled(&GetDocument())) {
       link_ = LinkImport::Create(this);
     } else if (rel_attribute_.IsManifest()) {
       link_ = LinkManifest::Create(this);
diff --git a/third_party/blink/renderer/core/html/html_link_element.idl b/third_party/blink/renderer/core/html/html_link_element.idl
index 933f8083..a8764048 100644
--- a/third_party/blink/renderer/core/html/html_link_element.idl
+++ b/third_party/blink/renderer/core/html/html_link_element.idl
@@ -51,7 +51,7 @@
 
     // HTML Imports
     // https://w3c.github.io/webcomponents/spec/imports/#interface-import
-    [RuntimeEnabled=HTMLImports] readonly attribute Document? import;
+    [OriginTrialEnabled=HTMLImports] readonly attribute Document? import;
 
     // Subresource Integrity
     // https://w3c.github.io/webappsec-subresource-integrity/#HTMLLinkElement
diff --git a/third_party/blink/renderer/core/input/event_handler.cc b/third_party/blink/renderer/core/input/event_handler.cc
index e27e2f2..532a638 100644
--- a/third_party/blink/renderer/core/input/event_handler.cc
+++ b/third_party/blink/renderer/core/input/event_handler.cc
@@ -178,7 +178,7 @@
 void EventHandler::Trace(blink::Visitor* visitor) {
   visitor->Trace(frame_);
   visitor->Trace(selection_controller_);
-  visitor->Trace(capturing_mouse_events_node_);
+  visitor->Trace(capturing_mouse_events_element_);
   visitor->Trace(last_mouse_move_event_subframe_);
   visitor->Trace(last_scrollbar_under_mouse_);
   visitor->Trace(drag_target_);
@@ -203,7 +203,7 @@
   drag_target_ = nullptr;
   should_only_fire_drag_over_event_ = false;
   last_mouse_down_user_gesture_token_ = nullptr;
-  capturing_mouse_events_node_ = nullptr;
+  capturing_mouse_events_element_ = nullptr;
   pointer_event_manager_->Clear();
   scroll_manager_->Clear();
   gesture_manager_->Clear();
@@ -405,7 +405,7 @@
   // node, don't treat this as a selection. Note calling
   // ComputeVisibleSelectionInDOMTreeDeprecated may update layout.
   const bool mouse_selection =
-      !capturing_mouse_events_node_ &&
+      !capturing_mouse_events_element_ &&
       mouse_event_manager_->MousePressed() &&
       GetSelectionController().MouseDownMayStartSelect() &&
       !mouse_event_manager_->MouseDownMayStartDrag() &&
@@ -610,7 +610,7 @@
     return WebInputEventResult::kHandledSuppressed;
 
   if (event_handler_will_reset_capturing_mouse_events_node_)
-    capturing_mouse_events_node_ = nullptr;
+    capturing_mouse_events_element_ = nullptr;
   mouse_event_manager_->HandleMousePressEventUpdateStates(mouse_event);
   if (!frame_->View())
     return WebInputEventResult::kNotHandled;
@@ -644,7 +644,7 @@
         subframe->GetEventHandler().mouse_event_manager_->CapturesDragging());
     if (mouse_event_manager_->MousePressed() &&
         mouse_event_manager_->CapturesDragging()) {
-      capturing_mouse_events_node_ = mev.InnerNode();
+      capturing_mouse_events_element_ = mev.InnerElement();
       event_handler_will_reset_capturing_mouse_events_node_ = true;
     }
     mouse_event_manager_->InvalidateClick();
@@ -680,7 +680,7 @@
     frame_->Selection().SetCaretBlinkingSuspended(true);
 
   WebInputEventResult event_result = DispatchMousePointerEvent(
-      WebInputEvent::kPointerDown, mev.InnerNode(), mev.CanvasRegionId(),
+      WebInputEvent::kPointerDown, mev.InnerElement(), mev.CanvasRegionId(),
       mev.Event(), Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
 
   // Disabled form controls still need to resize the scrollable area.
@@ -841,7 +841,7 @@
         WebInputEvent::Modifiers::kRelativeMotionEvent)) {
     mouse_event_manager_->ClearDragHeuristicState();
     if (event_handler_will_reset_capturing_mouse_events_node_)
-      capturing_mouse_events_node_ = nullptr;
+      capturing_mouse_events_element_ = nullptr;
     CaptureMouseEventsToWidget(false);
   }
 
@@ -925,7 +925,7 @@
   WebInputEventResult event_result = WebInputEventResult::kNotHandled;
   bool is_remote_frame = false;
   LocalFrame* new_subframe = event_handling_util::GetTargetSubframe(
-      mev, capturing_mouse_events_node_.Get(), &is_remote_frame);
+      mev, capturing_mouse_events_element_.Get(), &is_remote_frame);
 
   // We want mouseouts to happen first, from the inside out.  First send a
   // move event to the last subframe so that it will fire mouseouts.
@@ -941,8 +941,8 @@
   if (new_subframe) {
     // Update over/out state before passing the event to the subframe.
     pointer_event_manager_->SendMouseAndPointerBoundaryEvents(
-        EffectiveMouseEventTargetNode(mev.InnerNode()), mev.CanvasRegionId(),
-        mev.Event());
+        EffectiveMouseEventTargetElement(mev.InnerElement()),
+        mev.CanvasRegionId(), mev.Event());
 
     // Event dispatch in sendMouseAndPointerBoundaryEvents may have caused the
     // subframe of the target node to be detached from its LocalFrameView, in
@@ -974,7 +974,7 @@
     return event_result;
 
   event_result = DispatchMousePointerEvent(
-      WebInputEvent::kPointerMove, mev.InnerNode(), mev.CanvasRegionId(),
+      WebInputEvent::kPointerMove, mev.InnerElement(), mev.CanvasRegionId(),
       mev.Event(), coalesced_events, predicted_events);
   // TODO(crbug.com/346473): Since there is no default action for the mousemove
   // event we should consider doing drag&drop even when js cancels the
@@ -1015,8 +1015,8 @@
   if (frame_set_being_resized_) {
     CaptureMouseEventsToWidget(false);
     return mouse_event_manager_->SetMousePositionAndDispatchMouseEvent(
-        EffectiveMouseEventTargetNode(frame_set_being_resized_.Get()), String(),
-        event_type_names::kMouseup, mouse_event);
+        EffectiveMouseEventTargetElement(frame_set_being_resized_.Get()),
+        String(), event_type_names::kMouseup, mouse_event);
   }
 
   if (last_scrollbar_under_mouse_) {
@@ -1024,7 +1024,7 @@
     last_scrollbar_under_mouse_->MouseUp(mouse_event);
     CaptureMouseEventsToWidget(false);
     return DispatchMousePointerEvent(
-        WebInputEvent::kPointerUp, mouse_event_manager_->GetNodeUnderMouse(),
+        WebInputEvent::kPointerUp, mouse_event_manager_->GetElementUnderMouse(),
         String(), mouse_event, Vector<WebMouseEvent>(),
         Vector<WebMouseEvent>());
   }
@@ -1039,9 +1039,9 @@
                                                     mouse_event);
   Element* mouse_release_target = mev.InnerElement();
   LocalFrame* subframe = event_handling_util::GetTargetSubframe(
-      mev, capturing_mouse_events_node_.Get());
+      mev, capturing_mouse_events_element_.Get());
   if (event_handler_will_reset_capturing_mouse_events_node_)
-    capturing_mouse_events_node_ = nullptr;
+    capturing_mouse_events_element_ = nullptr;
   if (subframe)
     return PassMouseReleaseEventToSubframe(mev, subframe);
 
@@ -1063,7 +1063,7 @@
   }
 
   WebInputEventResult event_result = DispatchMousePointerEvent(
-      WebInputEvent::kPointerUp, mev.InnerNode(), mev.CanvasRegionId(),
+      WebInputEvent::kPointerUp, mev.InnerElement(), mev.CanvasRegionId(),
       mev.Event(), Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
 
   WebInputEventResult click_event_result =
@@ -1230,7 +1230,7 @@
 void EventHandler::ClearDragState() {
   scroll_manager_->StopAutoscroll();
   drag_target_ = nullptr;
-  capturing_mouse_events_node_ = nullptr;
+  capturing_mouse_events_element_ = nullptr;
   should_only_fire_drag_over_event_ = false;
 }
 
@@ -1242,23 +1242,18 @@
   mouse_event_manager_->RecomputeMouseHoverState();
 }
 
-void EventHandler::SetCapturingMouseEventsNode(Node* n) {
+void EventHandler::SetCapturingMouseEventsElement(Element* n) {
   CaptureMouseEventsToWidget(n);
-  capturing_mouse_events_node_ = n;
+  capturing_mouse_events_element_ = n;
 }
 
-Node* EventHandler::EffectiveMouseEventTargetNode(Node* target_node) {
-  Node* new_node_under_mouse = target_node;
-
-  if (capturing_mouse_events_node_) {
-    new_node_under_mouse = capturing_mouse_events_node_.Get();
-  } else {
-    // If the target node is a text node, dispatch on the parent node -
-    // rdar://4196646
-    if (new_node_under_mouse && new_node_under_mouse->IsTextNode())
-      new_node_under_mouse = FlatTreeTraversal::Parent(*new_node_under_mouse);
+Element* EventHandler::EffectiveMouseEventTargetElement(
+    Element* target_element) {
+  Element* new_element_under_mouse = target_element;
+  if (capturing_mouse_events_element_) {
+    new_element_under_mouse = capturing_mouse_events_element_.Get();
   }
-  return new_node_under_mouse;
+  return new_element_under_mouse;
 }
 
 bool EventHandler::IsTouchPointerIdActiveOnFrame(int pointer_id,
@@ -1281,7 +1276,7 @@
          RootFrameTouchPointerActiveInCurrentFrame(pointer_id);
 }
 
-void EventHandler::SetPointerCapture(int pointer_id, EventTarget* target) {
+void EventHandler::SetPointerCapture(int pointer_id, Element* target) {
   // TODO(crbug.com/591387): This functionality should be per page not per
   // frame.
   if (RootFrameTouchPointerActiveInCurrentFrame(pointer_id)) {
@@ -1292,7 +1287,7 @@
   }
 }
 
-void EventHandler::ReleasePointerCapture(int pointer_id, EventTarget* target) {
+void EventHandler::ReleasePointerCapture(int pointer_id, Element* target) {
   if (RootFrameTouchPointerActiveInCurrentFrame(pointer_id)) {
     frame_->LocalFrameRoot().GetEventHandler().ReleasePointerCapture(pointer_id,
                                                                      target);
@@ -1306,7 +1301,7 @@
 }
 
 bool EventHandler::HasPointerCapture(int pointer_id,
-                                     const EventTarget* target) const {
+                                     const Element* target) const {
   if (RootFrameTouchPointerActiveInCurrentFrame(pointer_id)) {
     return frame_->LocalFrameRoot().GetEventHandler().HasPointerCapture(
         pointer_id, target);
@@ -1316,7 +1311,7 @@
 }
 
 bool EventHandler::HasProcessedPointerCapture(int pointer_id,
-                                              const EventTarget* target) const {
+                                              const Element* target) const {
   return pointer_event_manager_->HasProcessedPointerCapture(pointer_id, target);
 }
 
@@ -1326,22 +1321,22 @@
       mouse_event);
 }
 
-void EventHandler::ElementRemoved(EventTarget* target) {
+void EventHandler::ElementRemoved(Element* target) {
   pointer_event_manager_->ElementRemoved(target);
   if (target)
-    mouse_wheel_event_manager_->ElementRemoved(target->ToNode());
+    mouse_wheel_event_manager_->ElementRemoved(target);
 }
 
 WebInputEventResult EventHandler::DispatchMousePointerEvent(
     const WebInputEvent::Type event_type,
-    Node* target_node,
+    Element* target_element,
     const String& canvas_region_id,
     const WebMouseEvent& mouse_event,
     const Vector<WebMouseEvent>& coalesced_events,
     const Vector<WebMouseEvent>& predicted_events) {
   const auto& event_result = pointer_event_manager_->SendMousePointerEvent(
-      EffectiveMouseEventTargetNode(target_node), canvas_region_id, event_type,
-      mouse_event, coalesced_events, predicted_events);
+      EffectiveMouseEventTargetElement(target_element), canvas_region_id,
+      event_type, mouse_event, coalesced_events, predicted_events);
   return event_result;
 }
 
@@ -1647,8 +1642,9 @@
   // Insert the frame from the disagreement between last frames and entered
   // frames.
   while (exited_frame_in_document) {
-    Node* last_node_under_tap = exited_frame_in_document->GetEventHandler()
-                                    .mouse_event_manager_->GetNodeUnderMouse();
+    Node* last_node_under_tap =
+        exited_frame_in_document->GetEventHandler()
+            .mouse_event_manager_->GetElementUnderMouse();
     if (!last_node_under_tap)
       break;
 
@@ -1688,8 +1684,8 @@
   wtf_size_t index_exited_frame_chain = exited_frame_chain.size();
   while (index_exited_frame_chain) {
     LocalFrame* leave_frame = exited_frame_chain[--index_exited_frame_chain];
-    leave_frame->GetEventHandler().mouse_event_manager_->SetNodeUnderMouse(
-        EffectiveMouseEventTargetNode(nullptr), String(), fake_mouse_move);
+    leave_frame->GetEventHandler().mouse_event_manager_->SetElementUnderMouse(
+        EffectiveMouseEventTargetElement(nullptr), String(), fake_mouse_move);
   }
 
   // update the mouseover/mouseenter event
@@ -1699,8 +1695,8 @@
     if (parent_frame && parent_frame->IsLocalFrame()) {
       ToLocalFrame(parent_frame)
           ->GetEventHandler()
-          .mouse_event_manager_->SetNodeUnderMouse(
-              EffectiveMouseEventTargetNode(ToHTMLFrameOwnerElement(
+          .mouse_event_manager_->SetElementUnderMouse(
+              EffectiveMouseEventTargetElement(ToHTMLFrameOwnerElement(
                   entered_frame_chain[index_entered_frame_chain]->Owner())),
               String(), fake_mouse_move);
     }
@@ -1870,7 +1866,7 @@
 
 WebInputEventResult EventHandler::SendContextMenuEvent(
     const WebMouseEvent& event,
-    Node* override_target_node) {
+    Element* override_target_element) {
   LocalFrameView* v = frame_->View();
   if (!v)
     return WebInputEventResult::kNotHandled;
@@ -1894,10 +1890,10 @@
 
   GetSelectionController().SendContextMenuEvent(mev, position_in_contents);
 
-  Node* target_node =
-      override_target_node ? override_target_node : mev.InnerNode();
+  Element* target_element =
+      override_target_element ? override_target_element : mev.InnerElement();
   return mouse_event_manager_->DispatchMouseEvent(
-      EffectiveMouseEventTargetNode(target_node),
+      EffectiveMouseEventTargetElement(target_element),
       event_type_names::kContextmenu, event,
       mev.GetHitTestResult().CanvasRegionId(), nullptr, nullptr);
 }
diff --git a/third_party/blink/renderer/core/input/event_handler.h b/third_party/blink/renderer/core/input/event_handler.h
index d268bfd..32e3ca6 100644
--- a/third_party/blink/renderer/core/input/event_handler.h
+++ b/third_party/blink/renderer/core/input/event_handler.h
@@ -60,7 +60,6 @@
 class PaintLayer;
 class Element;
 class Event;
-class EventTarget;
 template <typename EventType>
 class EventWithHitTestResults;
 class FloatQuad;
@@ -113,8 +112,8 @@
     return mouse_event_manager_->IsMousePositionUnknown();
   }
   void ClearMouseEventManager() const { mouse_event_manager_->Clear(); }
-  void SetCapturingMouseEventsNode(
-      Node*);  // A caller is responsible for resetting capturing node to 0.
+  void SetCapturingMouseEventsElement(
+      Element*);  // A caller is responsible for resetting capturing node to 0.
 
   WebInputEventResult UpdateDragAndDrop(const WebMouseEvent&, DataTransfer*);
   void CancelDragAndDrop(const WebMouseEvent&, DataTransfer*);
@@ -213,7 +212,7 @@
 
   WebInputEventResult SendContextMenuEvent(
       const WebMouseEvent&,
-      Node* override_target_node = nullptr);
+      Element* override_target_element = nullptr);
   WebInputEventResult ShowNonLocatedContextMenu(
       Element* override_target_element = nullptr,
       WebMenuSourceType = kMenuSourceNone);
@@ -221,14 +220,14 @@
   // Returns whether pointerId is active or not
   bool IsPointerEventActive(int);
 
-  void SetPointerCapture(int, EventTarget*);
-  void ReleasePointerCapture(int, EventTarget*);
+  void SetPointerCapture(int, Element*);
+  void ReleasePointerCapture(int, Element*);
   void ReleaseMousePointerCapture();
-  bool HasPointerCapture(int, const EventTarget*) const;
-  bool HasProcessedPointerCapture(int, const EventTarget*) const;
+  bool HasPointerCapture(int, const Element*) const;
+  bool HasProcessedPointerCapture(int, const Element*) const;
   void ProcessPendingPointerCaptureForPointerLock(const WebMouseEvent&);
 
-  void ElementRemoved(EventTarget*);
+  void ElementRemoved(Element*);
 
   void SetMouseDownMayStartAutoscroll();
 
@@ -353,13 +352,13 @@
 
   ScrollableArea* AssociatedScrollableArea(const PaintLayer*) const;
 
-  Node* EffectiveMouseEventTargetNode(Node*);
+  Element* EffectiveMouseEventTargetElement(Element*);
 
   // Dispatches ME after corresponding PE provided the PE has not been canceled.
   // The |mouse_event_type| arg must be one of {mousedown, mousemove, mouseup}.
   WebInputEventResult DispatchMousePointerEvent(
       const WebInputEvent::Type,
-      Node* target,
+      Element* target,
       const String& canvas_region_id,
       const WebMouseEvent&,
       const Vector<WebMouseEvent>& coalesced_events,
@@ -414,7 +413,7 @@
   // crbug.com/449649
   TaskRunnerTimer<EventHandler> cursor_update_timer_;
 
-  Member<Node> capturing_mouse_events_node_;
+  Member<Element> capturing_mouse_events_element_;
   bool event_handler_will_reset_capturing_mouse_events_node_;
 
   // Indicates whether the current widget is capturing mouse input.
diff --git a/third_party/blink/renderer/core/input/event_handling_util.h b/third_party/blink/renderer/core/input/event_handling_util.h
index fc457c2c..b5e8ead 100644
--- a/third_party/blink/renderer/core/input/event_handling_util.h
+++ b/third_party/blink/renderer/core/input/event_handling_util.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_INPUT_EVENT_HANDLING_UTIL_H_
 
 #include "third_party/blink/public/platform/web_input_event_result.h"
+#include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
 #include "third_party/blink/renderer/core/page/event_with_hit_test_results.h"
@@ -57,11 +58,11 @@
 
  public:
   void Trace(blink::Visitor* visitor) {
-    visitor->Trace(target_node);
+    visitor->Trace(target_element);
     visitor->Trace(target_frame);
   }
 
-  Member<Node> target_node;
+  Member<Element> target_element;
   Member<LocalFrame> target_frame;
   String region;
 };
diff --git a/third_party/blink/renderer/core/input/gesture_manager.cc b/third_party/blink/renderer/core/input/gesture_manager.cc
index b148e1b..20c2348 100644
--- a/third_party/blink/renderer/core/input/gesture_manager.cc
+++ b/third_party/blink/renderer/core/input/gesture_manager.cc
@@ -176,7 +176,7 @@
             WebInputEvent::Modifiers::kIsCompatibilityEventForTouch),
         gesture_event.TimeStamp());
     mouse_event_manager_->SetMousePositionAndDispatchMouseEvent(
-        current_hit_test.InnerNode(), current_hit_test.CanvasRegionId(),
+        current_hit_test.InnerElement(), current_hit_test.CanvasRegionId(),
         event_type_names::kMousemove, fake_mouse_move);
   }
 
@@ -228,7 +228,7 @@
 
     mouse_down_event_result =
         mouse_event_manager_->SetMousePositionAndDispatchMouseEvent(
-            current_hit_test.InnerNode(), current_hit_test.CanvasRegionId(),
+            current_hit_test.InnerElement(), current_hit_test.CanvasRegionId(),
             event_type_names::kMousedown, fake_mouse_down);
     selection_controller_->InitializeSelectionState();
     if (mouse_down_event_result == WebInputEventResult::kNotHandled) {
@@ -275,8 +275,9 @@
       suppress_mouse_events_from_gestures_
           ? WebInputEventResult::kHandledSuppressed
           : mouse_event_manager_->SetMousePositionAndDispatchMouseEvent(
-                current_hit_test.InnerNode(), current_hit_test.CanvasRegionId(),
-                event_type_names::kMouseup, fake_mouse_up);
+                current_hit_test.InnerElement(),
+                current_hit_test.CanvasRegionId(), event_type_names::kMouseup,
+                fake_mouse_up);
 
   WebInputEventResult click_event_result = WebInputEventResult::kNotHandled;
   if (tapped_element) {
@@ -290,9 +291,13 @@
       tapped_element->UpdateDistributionForFlatTreeTraversal();
       Node* click_target_node = current_hit_test.InnerNode()->CommonAncestor(
           *tapped_element, event_handling_util::ParentForClickEvent);
+      Element* click_target_element = nullptr;
+      if (click_target_node && click_target_node->IsElementNode())
+        click_target_element = ToElement(click_target_node);
+
       click_event_result =
           mouse_event_manager_->SetMousePositionAndDispatchMouseEvent(
-              click_target_node, String(), event_type_names::kClick,
+              click_target_element, String(), event_type_names::kClick,
               fake_mouse_up);
     }
     mouse_event_manager_->SetClickElement(nullptr);
@@ -402,7 +407,7 @@
             modifiers | WebInputEvent::kIsCompatibilityEventForTouch),
         gesture_event.TimeStamp());
     mouse_event_manager_->SetMousePositionAndDispatchMouseEvent(
-        targeted_event.GetHitTestResult().InnerNode(),
+        targeted_event.GetHitTestResult().InnerElement(),
         targeted_event.CanvasRegionId(), event_type_names::kMousemove,
         fake_mouse_move);
   }
diff --git a/third_party/blink/renderer/core/input/mouse_event_manager.cc b/third_party/blink/renderer/core/input/mouse_event_manager.cc
index 9868455..908519a 100644
--- a/third_party/blink/renderer/core/input/mouse_event_manager.cc
+++ b/third_party/blink/renderer/core/input/mouse_event_manager.cc
@@ -119,7 +119,7 @@
 }
 
 void MouseEventManager::Clear() {
-  node_under_mouse_ = nullptr;
+  element_under_mouse_ = nullptr;
   mouse_press_node_ = nullptr;
   mouse_down_may_start_autoscroll_ = false;
   mouse_down_may_start_drag_ = false;
@@ -146,7 +146,7 @@
 void MouseEventManager::Trace(blink::Visitor* visitor) {
   visitor->Trace(frame_);
   visitor->Trace(scroll_manager_);
-  visitor->Trace(node_under_mouse_);
+  visitor->Trace(element_under_mouse_);
   visitor->Trace(mouse_press_node_);
   visitor->Trace(click_element_);
   visitor->Trace(mouse_down_element_);
@@ -287,17 +287,12 @@
 }
 
 WebInputEventResult MouseEventManager::SetMousePositionAndDispatchMouseEvent(
-    Node* target_node,
+    Element* target_element,
     const String& canvas_region_id,
     const AtomicString& event_type,
     const WebMouseEvent& web_mouse_event) {
-  // If the target node is a text node, dispatch on the parent node.
-  if (target_node && target_node->IsTextNode())
-    target_node = FlatTreeTraversal::Parent(*target_node);
-
-  SetNodeUnderMouse(target_node, canvas_region_id, web_mouse_event);
-
-  return DispatchMouseEvent(node_under_mouse_, event_type, web_mouse_event,
+  SetElementUnderMouse(target_element, canvas_region_id, web_mouse_event);
+  return DispatchMouseEvent(element_under_mouse_, event_type, web_mouse_event,
                             canvas_region_id, nullptr, nullptr);
 }
 
@@ -413,17 +408,17 @@
   fake_mouse_move_event_timer_.Stop();
 }
 
-void MouseEventManager::SetNodeUnderMouse(
-    Node* target,
+void MouseEventManager::SetElementUnderMouse(
+    Element* target,
     const String& canvas_region_id,
     const WebMouseEvent& web_mouse_event) {
-  Node* last_node_under_mouse = node_under_mouse_;
-  node_under_mouse_ = target;
+  Element* last_element_under_mouse = element_under_mouse_;
+  element_under_mouse_ = target;
 
   PaintLayer* layer_for_last_node =
-      event_handling_util::LayerForNode(last_node_under_mouse);
+      event_handling_util::LayerForNode(last_element_under_mouse);
   PaintLayer* layer_for_node_under_mouse =
-      event_handling_util::LayerForNode(node_under_mouse_.Get());
+      event_handling_util::LayerForNode(element_under_mouse_.Get());
   Page* page = frame_->GetPage();
 
   if (page && (layer_for_last_node &&
@@ -445,13 +440,13 @@
       scrollable_area_for_node_under_mouse->MouseEnteredContentArea();
   }
 
-  if (last_node_under_mouse &&
-      last_node_under_mouse->GetDocument() != frame_->GetDocument()) {
-    last_node_under_mouse = nullptr;
+  if (last_element_under_mouse &&
+      last_element_under_mouse->GetDocument() != frame_->GetDocument()) {
+    last_element_under_mouse = nullptr;
   }
 
-  SendBoundaryEvents(last_node_under_mouse, node_under_mouse_, canvas_region_id,
-                     web_mouse_event);
+  SendBoundaryEvents(last_element_under_mouse, element_under_mouse_,
+                     canvas_region_id, web_mouse_event);
 }
 
 void MouseEventManager::NodeChildrenWillBeRemoved(ContainerNode& container) {
@@ -477,8 +472,8 @@
   }
 }
 
-Node* MouseEventManager::GetNodeUnderMouse() {
-  return node_under_mouse_;
+Element* MouseEventManager::GetElementUnderMouse() {
+  return element_under_mouse_;
 }
 
 WebInputEventResult MouseEventManager::HandleMouseFocus(
@@ -496,12 +491,7 @@
   // The layout needs to be up to date to determine if an element is focusable.
   frame_->GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
 
-  Element* element = nullptr;
-  if (node_under_mouse_) {
-    element = node_under_mouse_->IsElementNode()
-                  ? ToElement(node_under_mouse_)
-                  : node_under_mouse_->ParentOrShadowHostElement();
-  }
+  Element* element = element_under_mouse_;
   for (; element; element = element->ParentOrShadowHostElement()) {
     if (element->IsFocusable() && element->IsFocusedElementInDocument())
       return WebInputEventResult::kNotHandled;
diff --git a/third_party/blink/renderer/core/input/mouse_event_manager.h b/third_party/blink/renderer/core/input/mouse_event_manager.h
index c234d92..f16e533 100644
--- a/third_party/blink/renderer/core/input/mouse_event_manager.h
+++ b/third_party/blink/renderer/core/input/mouse_event_manager.h
@@ -54,7 +54,7 @@
                                          bool check_for_listener = false);
 
   WebInputEventResult SetMousePositionAndDispatchMouseEvent(
-      Node* target_node,
+      Element* target_element,
       const String& canvas_region_id,
       const AtomicString& event_type,
       const WebMouseEvent&);
@@ -79,9 +79,9 @@
                           const String& canvas_region_id,
                           const WebMouseEvent&);
 
-  void SetNodeUnderMouse(Node*,
-                         const String& canvas_region_id,
-                         const WebMouseEvent&);
+  void SetElementUnderMouse(Element*,
+                            const String& canvas_region_id,
+                            const WebMouseEvent&);
 
   WebInputEventResult HandleMouseFocus(
       const HitTestResult&,
@@ -129,7 +129,7 @@
 
   // TODO: These functions ideally should be private but the code needs more
   // refactoring to be able to remove the dependency from EventHandler.
-  Node* GetNodeUnderMouse();
+  Element* GetElementUnderMouse();
   bool IsMousePositionUnknown();
   // TODO(aelias): Make LastKnownMousePosition return FloatPoint.
   IntPoint LastKnownMousePosition();
@@ -217,7 +217,7 @@
   // The effective position of the mouse pointer.
   // See
   // https://w3c.github.io/pointerevents/#dfn-tracking-the-effective-position-of-the-legacy-mouse-pointer.
-  Member<Node> node_under_mouse_;
+  Member<Element> element_under_mouse_;
 
   // The last mouse movement position this frame has seen in viewport
   // coordinates.
diff --git a/third_party/blink/renderer/core/input/pointer_event_manager.cc b/third_party/blink/renderer/core/input/pointer_event_manager.cc
index fffde329..d8aadfc 100644
--- a/third_party/blink/renderer/core/input/pointer_event_manager.cc
+++ b/third_party/blink/renderer/core/input/pointer_event_manager.cc
@@ -77,7 +77,7 @@
   non_hovering_pointers_canceled_ = false;
   pointer_event_factory_.Clear();
   touch_ids_for_canceled_pointerdowns_.clear();
-  node_under_pointer_.clear();
+  element_under_pointer_.clear();
   pointer_capture_target_.clear();
   pending_pointer_capture_target_.clear();
   user_gesture_holder_.reset();
@@ -86,7 +86,7 @@
 
 void PointerEventManager::Trace(blink::Visitor* visitor) {
   visitor->Trace(frame_);
-  visitor->Trace(node_under_pointer_);
+  visitor->Trace(element_under_pointer_);
   visitor->Trace(pointer_capture_target_);
   visitor->Trace(pending_pointer_capture_target_);
   visitor->Trace(touch_event_manager_);
@@ -184,16 +184,16 @@
   return WebInputEventResult::kNotHandled;
 }
 
-EventTarget* PointerEventManager::GetEffectiveTargetForPointerEvent(
-    EventTarget* target,
+Element* PointerEventManager::GetEffectiveTargetForPointerEvent(
+    Element* target,
     int pointer_id) {
-  if (EventTarget* capturing_target = GetCapturingNode(pointer_id))
+  if (Element* capturing_target = GetCapturingElement(pointer_id))
     return capturing_target;
   return target;
 }
 
 void PointerEventManager::SendMouseAndPointerBoundaryEvents(
-    Node* entered_node,
+    Element* entered_element,
     const String& canvas_region_id,
     const WebMouseEvent& mouse_event) {
   // Mouse event type does not matter as this pointerevent will only be used
@@ -215,7 +215,7 @@
         mouse_event.pointer_type)] = false;
   }
 
-  ProcessCaptureAndPositionOfPointerEvent(dummy_pointer_event, entered_node,
+  ProcessCaptureAndPositionOfPointerEvent(dummy_pointer_event, entered_element,
                                           canvas_region_id, &mouse_event);
 }
 
@@ -227,22 +227,22 @@
   boundary_event_dispatcher.SendBoundaryEvents(exited_target, entered_target);
 }
 
-void PointerEventManager::SetNodeUnderPointer(PointerEvent* pointer_event,
-                                              EventTarget* target) {
-  if (node_under_pointer_.Contains(pointer_event->pointerId())) {
+void PointerEventManager::SetElementUnderPointer(PointerEvent* pointer_event,
+                                                 Element* target) {
+  if (element_under_pointer_.Contains(pointer_event->pointerId())) {
     EventTargetAttributes node =
-        node_under_pointer_.at(pointer_event->pointerId());
+        element_under_pointer_.at(pointer_event->pointerId());
     if (!target) {
-      node_under_pointer_.erase(pointer_event->pointerId());
+      element_under_pointer_.erase(pointer_event->pointerId());
     } else if (target !=
-               node_under_pointer_.at(pointer_event->pointerId()).target) {
-      node_under_pointer_.Set(pointer_event->pointerId(),
-                              EventTargetAttributes(target));
+               element_under_pointer_.at(pointer_event->pointerId()).target) {
+      element_under_pointer_.Set(pointer_event->pointerId(),
+                                 EventTargetAttributes(target));
     }
     SendBoundaryEvents(node.target, target, pointer_event);
   } else if (target) {
-    node_under_pointer_.insert(pointer_event->pointerId(),
-                               EventTargetAttributes(target));
+    element_under_pointer_.insert(pointer_event->pointerId(),
+                                  EventTargetAttributes(target));
     SendBoundaryEvents(nullptr, target, pointer_event);
   }
 }
@@ -281,9 +281,9 @@
   for (auto pointer_event : canceled_pointer_events) {
     // If we are sending a pointercancel we have sent the pointerevent to some
     // target before.
-    DCHECK(node_under_pointer_.Contains(pointer_event->pointerId()));
-    EventTarget* target =
-        node_under_pointer_.at(pointer_event->pointerId()).target;
+    DCHECK(element_under_pointer_.Contains(pointer_event->pointerId()));
+    Element* target =
+        element_under_pointer_.at(pointer_event->pointerId()).target;
 
     DispatchPointerEvent(
         GetEffectiveTargetForPointerEvent(target, pointer_event->pointerId()),
@@ -373,34 +373,27 @@
         LayoutPoint(web_pointer_event.PositionInWidget())));
     HitTestResult hit_test_tesult =
         frame_->GetEventHandler().HitTestResultAtLocation(location, hit_type);
-    Node* node = hit_test_tesult.InnerNode();
-    if (node) {
-      pointer_event_target.target_frame = node->GetDocument().GetFrame();
-      if (auto* canvas = ToHTMLCanvasElementOrNull(node)) {
+    Element* target = hit_test_tesult.InnerElement();
+    if (target) {
+      pointer_event_target.target_frame = target->GetDocument().GetFrame();
+      if (auto* canvas = ToHTMLCanvasElementOrNull(target)) {
         HitTestCanvasResult* hit_test_canvas_result =
             canvas->GetControlAndIdIfHitRegionExists(
                 hit_test_tesult.PointInInnerNodeFrame());
         if (hit_test_canvas_result->GetControl())
-          node = hit_test_canvas_result->GetControl();
+          target = hit_test_canvas_result->GetControl();
         pointer_event_target.region = hit_test_canvas_result->GetId();
       }
-      // TODO(crbug.com/612456): We need to investigate whether pointer
-      // events should go to text nodes or not. If so we need to
-      // update the mouse code as well. Also this logic looks similar
-      // to the one in TouchEventManager. We should be able to
-      // refactor it better after this investigation.
-      if (node->IsTextNode())
-        node = FlatTreeTraversal::Parent(*node);
-      pointer_event_target.target_node = node;
+      pointer_event_target.target_element = target;
     }
   } else {
-    // Set the target of pointer event to the captured node as this
+    // Set the target of pointer event to the captured element as this
     // pointer is captured otherwise it would have gone to the if block
     // and perform a hit-test.
-    pointer_event_target.target_node =
-        pending_pointer_capture_target_.at(pointer_id)->ToNode();
+    pointer_event_target.target_element =
+        pending_pointer_capture_target_.at(pointer_id);
     pointer_event_target.target_frame =
-        pointer_event_target.target_node->GetDocument().GetFrame();
+        pointer_event_target.target_element->GetDocument().GetFrame();
   }
   return pointer_event_target;
 }
@@ -414,15 +407,15 @@
             WebInputEvent::Type::kPointerCausedUaAction);
 
   WebInputEventResult result = WebInputEventResult::kHandledSystem;
-  if (pointer_event_target.target_node && pointer_event_target.target_frame &&
-      !non_hovering_pointers_canceled_) {
+  if (pointer_event_target.target_element &&
+      pointer_event_target.target_frame && !non_hovering_pointers_canceled_) {
     PointerEvent* pointer_event = pointer_event_factory_.Create(
         web_pointer_event, coalesced_events, predicted_events,
-        pointer_event_target.target_node
-            ? pointer_event_target.target_node->GetDocument().domWindow()
+        pointer_event_target.target_element
+            ? pointer_event_target.target_element->GetDocument().domWindow()
             : nullptr);
 
-    result = SendTouchPointerEvent(pointer_event_target.target_node,
+    result = SendTouchPointerEvent(pointer_event_target.target_element,
                                    pointer_event, web_pointer_event.hovering);
 
     // If a pointerdown has been canceled, queue the unique id to allow
@@ -442,7 +435,7 @@
 }
 
 WebInputEventResult PointerEventManager::SendTouchPointerEvent(
-    EventTarget* target,
+    Element* target,
     PointerEvent* pointer_event,
     bool hovering) {
   if (non_hovering_pointers_canceled_)
@@ -516,7 +509,7 @@
       }
       target = pointer_locked_element;
     } else {
-      target = ComputePointerEventTarget(event).target_node;
+      target = ComputePointerEventTarget(event).target_element;
     }
 
     PointerEvent* pointer_event =
@@ -627,7 +620,7 @@
 }
 
 WebInputEventResult PointerEventManager::SendMousePointerEvent(
-    Node* target,
+    Element* target,
     const String& canvas_region_id,
     const WebInputEvent::Type event_type,
     const WebMouseEvent& mouse_event,
@@ -674,7 +667,7 @@
     }
   }
 
-  EventTarget* pointer_event_target = ProcessCaptureAndPositionOfPointerEvent(
+  Element* pointer_event_target = ProcessCaptureAndPositionOfPointerEvent(
       pointer_event, target, canvas_region_id, &mouse_event);
 
   // Don't send fake mouse event to the DOM.
@@ -763,15 +756,15 @@
 
 bool PointerEventManager::GetPointerCaptureState(
     int pointer_id,
-    EventTarget** pointer_capture_target,
-    EventTarget** pending_pointer_capture_target) {
+    Element** pointer_capture_target,
+    Element** pending_pointer_capture_target) {
   PointerCapturingMap::const_iterator it;
 
   it = pointer_capture_target_.find(pointer_id);
-  EventTarget* pointer_capture_target_temp =
+  Element* pointer_capture_target_temp =
       (it != pointer_capture_target_.end()) ? it->value : nullptr;
   it = pending_pointer_capture_target_.find(pointer_id);
-  EventTarget* pending_pointercapture_target_temp =
+  Element* pending_pointercapture_target_temp =
       (it != pending_pointer_capture_target_.end()) ? it->value : nullptr;
 
   if (pointer_capture_target)
@@ -782,32 +775,31 @@
   return pointer_capture_target_temp != pending_pointercapture_target_temp;
 }
 
-EventTarget* PointerEventManager::ProcessCaptureAndPositionOfPointerEvent(
+Element* PointerEventManager::ProcessCaptureAndPositionOfPointerEvent(
     PointerEvent* pointer_event,
-    EventTarget* hit_test_target,
+    Element* hit_test_target,
     const String& canvas_region_id,
     const WebMouseEvent* mouse_event) {
   ProcessPendingPointerCapture(pointer_event);
 
   PointerCapturingMap::const_iterator it =
       pointer_capture_target_.find(pointer_event->pointerId());
-  if (EventTarget* pointercapture_target =
+  if (Element* pointercapture_target =
           (it != pointer_capture_target_.end()) ? it->value : nullptr)
     hit_test_target = pointercapture_target;
 
-  SetNodeUnderPointer(pointer_event, hit_test_target);
+  SetElementUnderPointer(pointer_event, hit_test_target);
   if (mouse_event) {
-    mouse_event_manager_->SetNodeUnderMouse(
-        hit_test_target ? hit_test_target->ToNode() : nullptr, canvas_region_id,
-        *mouse_event);
+    mouse_event_manager_->SetElementUnderMouse(hit_test_target,
+                                               canvas_region_id, *mouse_event);
   }
   return hit_test_target;
 }
 
 void PointerEventManager::ProcessPendingPointerCapture(
     PointerEvent* pointer_event) {
-  EventTarget* pointer_capture_target;
-  EventTarget* pending_pointer_capture_target;
+  Element* pointer_capture_target;
+  Element* pending_pointer_capture_target;
   const int pointer_id = pointer_event->pointerId();
   const bool is_capture_changed = GetPointerCaptureState(
       pointer_id, &pointer_capture_target, &pending_pointer_capture_target);
@@ -821,8 +813,8 @@
     // Re-target lostpointercapture to the document when the element is
     // no longer participating in the tree.
     EventTarget* target = pointer_capture_target;
-    if (target->ToNode() && !target->ToNode()->isConnected()) {
-      target = target->ToNode()->ownerDocument();
+    if (!pointer_capture_target->isConnected()) {
+      target = pointer_capture_target->ownerDocument();
     }
     DispatchPointerEvent(
         target, pointer_event_factory_.CreatePointerCaptureEvent(
@@ -830,7 +822,7 @@
   }
 
   if (pending_pointer_capture_target) {
-    SetNodeUnderPointer(pointer_event, pending_pointer_capture_target);
+    SetElementUnderPointer(pointer_event, pending_pointer_capture_target);
     DispatchPointerEvent(
         pending_pointer_capture_target,
         pointer_event_factory_.CreatePointerCaptureEvent(
@@ -852,7 +844,7 @@
 
 void PointerEventManager::RemoveTargetFromPointerCapturingMapping(
     PointerCapturingMap& map,
-    const EventTarget* target) {
+    const Element* target) {
   // We could have kept a reverse mapping to make this deletion possibly
   // faster but it adds some code complication which might not be worth of
   // the performance improvement considering there might not be a lot of
@@ -864,7 +856,7 @@
   }
 }
 
-EventTarget* PointerEventManager::GetCapturingNode(int pointer_id) {
+Element* PointerEventManager::GetCapturingElement(int pointer_id) {
   if (pointer_capture_target_.Contains(pointer_id))
     return pointer_capture_target_.at(pointer_id);
   return nullptr;
@@ -875,17 +867,16 @@
   if (pointer_event_factory_.Remove(pointer_id)) {
     pending_pointer_capture_target_.erase(pointer_id);
     pointer_capture_target_.erase(pointer_id);
-    node_under_pointer_.erase(pointer_id);
+    element_under_pointer_.erase(pointer_id);
   }
 }
 
-void PointerEventManager::ElementRemoved(EventTarget* target) {
+void PointerEventManager::ElementRemoved(Element* target) {
   RemoveTargetFromPointerCapturingMapping(pending_pointer_capture_target_,
                                           target);
 }
 
-void PointerEventManager::SetPointerCapture(int pointer_id,
-                                            EventTarget* target) {
+void PointerEventManager::SetPointerCapture(int pointer_id, Element* target) {
   UseCounter::Count(frame_, WebFeature::kPointerEventSetCapture);
   if (pointer_event_factory_.IsActiveButtonsState(pointer_id)) {
     if (pointer_id != dispatching_pointer_id_) {
@@ -897,7 +888,7 @@
 }
 
 void PointerEventManager::ReleasePointerCapture(int pointer_id,
-                                                EventTarget* target) {
+                                                Element* target) {
   // Only the element that is going to get the next pointer event can release
   // the capture. Note that this might be different from
   // |m_pointercaptureTarget|. |m_pointercaptureTarget| holds the element
@@ -914,13 +905,13 @@
 }
 
 bool PointerEventManager::HasPointerCapture(int pointer_id,
-                                            const EventTarget* target) const {
+                                            const Element* target) const {
   return pending_pointer_capture_target_.at(pointer_id) == target;
 }
 
 bool PointerEventManager::HasProcessedPointerCapture(
     int pointer_id,
-    const EventTarget* target) const {
+    const Element* target) const {
   return pointer_capture_target_.at(pointer_id) == target;
 }
 
@@ -942,12 +933,12 @@
   if (pointer_event_factory_.GetPointerType(pointer_id) !=
       WebPointerProperties::PointerType::kTouch)
     return false;
-  Node* last_node_receiving_event =
-      node_under_pointer_.Contains(pointer_id)
-          ? node_under_pointer_.at(pointer_id).target->ToNode()
+  Element* last_element_receiving_event =
+      element_under_pointer_.Contains(pointer_id)
+          ? element_under_pointer_.at(pointer_id).target
           : nullptr;
-  return last_node_receiving_event &&
-         last_node_receiving_event->GetDocument().GetFrame() == frame;
+  return last_element_receiving_event &&
+         last_element_receiving_event->GetDocument().GetFrame() == frame;
 }
 
 bool PointerEventManager::IsAnyTouchActive() const {
diff --git a/third_party/blink/renderer/core/input/pointer_event_manager.h b/third_party/blink/renderer/core/input/pointer_event_manager.h
index 479d018..3c8f7f7 100644
--- a/third_party/blink/renderer/core/input/pointer_event_manager.h
+++ b/third_party/blink/renderer/core/input/pointer_event_manager.h
@@ -44,7 +44,7 @@
   // and sets the newNodeUnderMouse if the capturing is set
   // in this function.
   WebInputEventResult SendMousePointerEvent(
-      Node* target,
+      Element* target,
       const String& canvas_region_id,
       const WebInputEvent::Type,
       const WebMouseEvent&,
@@ -57,7 +57,7 @@
   // leaving a frame. Note that normal mouse events (e.g. mousemove/down/up)
   // and their corresponding boundary events will be handled altogether by
   // sendMousePointerEvent function.
-  void SendMouseAndPointerBoundaryEvents(Node* entered_node,
+  void SendMouseAndPointerBoundaryEvents(Element* entered_element,
                                          const String& canvas_region_id,
                                          const WebMouseEvent&);
 
@@ -79,17 +79,17 @@
   // Resets the internal state of this object.
   void Clear();
 
-  void ElementRemoved(EventTarget*);
+  void ElementRemoved(Element*);
 
-  void SetPointerCapture(int, EventTarget*);
-  void ReleasePointerCapture(int, EventTarget*);
+  void SetPointerCapture(int, Element*);
+  void ReleasePointerCapture(int, Element*);
   void ReleaseMousePointerCapture();
 
   // See Element::hasPointerCapture(int).
-  bool HasPointerCapture(int, const EventTarget*) const;
+  bool HasPointerCapture(int, const Element*) const;
 
   // See Element::hasProcessedPointerCapture(int).
-  bool HasProcessedPointerCapture(int, const EventTarget*) const;
+  bool HasProcessedPointerCapture(int, const Element*) const;
 
   bool IsActive(const int) const;
 
@@ -118,7 +118,7 @@
 
  private:
   typedef HeapHashMap<int,
-                      Member<EventTarget>,
+                      Member<Element>,
                       WTF::IntHash<int>,
                       WTF::UnsignedWithZeroKeyHashTraits<int>>
       PointerCapturingMap;
@@ -127,10 +127,9 @@
 
    public:
     void Trace(blink::Visitor* visitor) { visitor->Trace(target); }
-    Member<EventTarget> target;
+    Member<Element> target;
     EventTargetAttributes() : target(nullptr) {}
-    EventTargetAttributes(EventTarget* target)
-        : target(target) {}
+    EventTargetAttributes(Element* target) : target(target) {}
   };
 
   class PointerEventBoundaryEventDispatcher : public BoundaryEventDispatcher {
@@ -179,14 +178,14 @@
       const event_handling_util::PointerEventTarget&);
 
   // Returns whether the event is consumed or not.
-  WebInputEventResult SendTouchPointerEvent(EventTarget*,
+  WebInputEventResult SendTouchPointerEvent(Element*,
                                             PointerEvent*,
                                             bool hovering);
 
   void SendBoundaryEvents(EventTarget* exited_target,
                           EventTarget* entered_target,
                           PointerEvent*);
-  void SetNodeUnderPointer(PointerEvent*, EventTarget*);
+  void SetElementUnderPointer(PointerEvent*, Element*);
 
   // Processes the assignment of |m_pointerCaptureTarget| from
   // |m_pendingPointerCaptureTarget| and sends the got/lostpointercapture
@@ -194,21 +193,21 @@
   // https://w3c.github.io/pointerevents/#process-pending-pointer-capture
   void ProcessPendingPointerCapture(PointerEvent*);
 
-  // Processes the capture state of a pointer, updates node under
+  // Processes the capture state of a pointer, updates element under
   // pointer, and sends corresponding boundary events for pointer if
   // setPointerPosition is true. It also sends corresponding boundary events
   // for mouse if sendMouseEvent is true.
   // Returns the target that the pointer event is supposed to be fired at.
-  EventTarget* ProcessCaptureAndPositionOfPointerEvent(
+  Element* ProcessCaptureAndPositionOfPointerEvent(
       PointerEvent*,
-      EventTarget* hit_test_target,
+      Element* hit_test_target,
       const String& canvas_region_id = String(),
       const WebMouseEvent* = nullptr);
 
   void RemoveTargetFromPointerCapturingMapping(PointerCapturingMap&,
-                                               const EventTarget*);
-  EventTarget* GetEffectiveTargetForPointerEvent(EventTarget*, int);
-  EventTarget* GetCapturingNode(int);
+                                               const Element*);
+  Element* GetEffectiveTargetForPointerEvent(Element*, int);
+  Element* GetCapturingElement(int);
   void RemovePointer(PointerEvent*);
   WebInputEventResult DispatchPointerEvent(EventTarget*,
                                            PointerEvent*,
@@ -216,8 +215,8 @@
   void ReleasePointerCapture(int);
   // Returns true if capture target and pending capture target were different.
   bool GetPointerCaptureState(int pointer_id,
-                              EventTarget** pointer_capture_target,
-                              EventTarget** pending_pointer_capture_target);
+                              Element** pointer_capture_target,
+                              Element** pending_pointer_capture_target);
 
   // Only adjust touch type primary pointer down.
   bool ShouldAdjustPointerEvent(const WebPointerEvent&) const;
@@ -242,16 +241,16 @@
 
   Deque<uint32_t> touch_ids_for_canceled_pointerdowns_;
 
-  // Note that this map keeps track of node under pointer with id=1 as well
+  // Note that this map keeps track of element under pointer with id=1 as well
   // which might be different than m_nodeUnderMouse in EventHandler. That one
   // keeps track of any compatibility mouse event positions but this map for
   // the pointer with id=1 is only taking care of true mouse related events.
-  using NodeUnderPointerMap =
+  using ElementUnderPointerMap =
       HeapHashMap<int,
                   EventTargetAttributes,
                   WTF::IntHash<int>,
                   WTF::UnsignedWithZeroKeyHashTraits<int>>;
-  NodeUnderPointerMap node_under_pointer_;
+  ElementUnderPointerMap element_under_pointer_;
 
   PointerCapturingMap pointer_capture_target_;
   PointerCapturingMap pending_pointer_capture_target_;
diff --git a/third_party/blink/renderer/core/input/touch_event_manager.cc b/third_party/blink/renderer/core/input/touch_event_manager.cc
index b066894..e3f6c92a 100644
--- a/third_party/blink/renderer/core/input/touch_event_manager.cc
+++ b/third_party/blink/renderer/core/input/touch_event_manager.cc
@@ -518,7 +518,7 @@
   touch_attribute_map_.Set(event.id,
                            MakeGarbageCollected<TouchPointAttributes>(event));
 
-  Node* touch_node = pointer_event_target.target_node;
+  Node* touch_node = pointer_event_target.target_element;
   String region = pointer_event_target.region;
 
   HitTestRequest::HitTestRequestType hit_type = HitTestRequest::kTouchEvent |
diff --git a/third_party/blink/renderer/core/layout/hit_test_result.cc b/third_party/blink/renderer/core/layout/hit_test_result.cc
index e9377496..c0ea73e8 100644
--- a/third_party/blink/renderer/core/layout/hit_test_result.cc
+++ b/third_party/blink/renderer/core/layout/hit_test_result.cc
@@ -481,6 +481,8 @@
     return nullptr;
   if (inner_node_->IsElementNode())
     return ToElement(inner_node_);
+  // TODO(nzolghadr): Add caching of this value instead of calculating it
+  // everytime.
   return FlatTreeTraversal::ParentElement(*inner_node_);
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_grid.cc b/third_party/blink/renderer/core/layout/layout_grid.cc
index 65c4f931..ce5c677 100644
--- a/third_party/blink/renderer/core/layout/layout_grid.cc
+++ b/third_party/blink/renderer/core/layout/layout_grid.cc
@@ -649,13 +649,15 @@
   // Add gutters as if there where only 1 auto repeat track. Gaps between auto
   // repeat tracks will be added later when computing the repetitions.
   LayoutUnit gap_size = GridGap(direction, available_size);
-  tracks_size += gap_size * track_sizes.size();
+  tracks_size +=
+      gap_size * (track_sizes.size() + auto_repeat_track_list_length - 1);
 
   LayoutUnit free_space = available_size.value() - tracks_size;
   if (free_space <= 0)
     return auto_repeat_track_list_length;
 
-  LayoutUnit auto_repeat_size_with_gap = auto_repeat_tracks_size + gap_size;
+  LayoutUnit auto_repeat_size_with_gap =
+      auto_repeat_tracks_size + gap_size * auto_repeat_track_list_length;
 
   size_t repetitions = 1 + (free_space / auto_repeat_size_with_gap).ToInt();
   free_space -= auto_repeat_size_with_gap * (repetitions - 1);
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index 6fa2e39..e6c7881 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -426,6 +426,7 @@
   // RemoteFrameClient implementation.
   void Navigate(const ResourceRequest&,
                 bool should_replace_current_entry,
+                bool is_opener_navigation,
                 mojom::blink::BlobURLTokenPtr) override {}
   unsigned BackForwardLength() override { return 0; }
   void CheckCompleted() override {}
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc
index 212a524..65f780d 100644
--- a/third_party/blink/renderer/core/timing/performance.cc
+++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -460,7 +460,8 @@
     return;
   AddResourceTiming(
       GenerateResourceTiming(*security_origin, info, *context),
-      !initiator_type.IsNull() ? initiator_type : info.InitiatorType());
+      !initiator_type.IsNull() ? initiator_type : info.InitiatorType(),
+      context->IsSecureContext());
 }
 
 WebResourceTimingInfo Performance::GenerateResourceTiming(
@@ -530,9 +531,10 @@
 }
 
 void Performance::AddResourceTiming(const WebResourceTimingInfo& info,
-                                    const AtomicString& initiator_type) {
-  PerformanceEntry* entry =
-      PerformanceResourceTiming::Create(info, time_origin_, initiator_type);
+                                    const AtomicString& initiator_type,
+                                    bool is_secure_context) {
+  PerformanceEntry* entry = PerformanceResourceTiming::Create(
+      info, time_origin_, initiator_type, is_secure_context);
   NotifyObserversOfEntry(*entry);
   // https://w3c.github.io/resource-timing/#dfn-add-a-performanceresourcetiming-entry
   if (CanAddResourceTimingEntry() &&
diff --git a/third_party/blink/renderer/core/timing/performance.h b/third_party/blink/renderer/core/timing/performance.h
index aa203ab7..c3b02082 100644
--- a/third_party/blink/renderer/core/timing/performance.h
+++ b/third_party/blink/renderer/core/timing/performance.h
@@ -148,7 +148,8 @@
       const ResourceTimingInfo&,
       ExecutionContext& context_for_use_counter);
   void AddResourceTiming(const WebResourceTimingInfo&,
-                         const AtomicString& initiator_type = g_null_atom);
+                         const AtomicString& initiator_type,
+                         bool is_secure_context);
 
   void NotifyNavigationTimingToObservers();
 
diff --git a/third_party/blink/renderer/core/timing/performance_resource_timing.cc b/third_party/blink/renderer/core/timing/performance_resource_timing.cc
index 9af7615..5bd7d15 100644
--- a/third_party/blink/renderer/core/timing/performance_resource_timing.cc
+++ b/third_party/blink/renderer/core/timing/performance_resource_timing.cc
@@ -45,7 +45,8 @@
 PerformanceResourceTiming::PerformanceResourceTiming(
     const WebResourceTimingInfo& info,
     TimeTicks time_origin,
-    const AtomicString& initiator_type)
+    const AtomicString& initiator_type,
+    bool is_secure_context)
     : PerformanceEntry(info.name,
                        Performance::MonotonicTimeToDOMHighResTimeStamp(
                            time_origin,
@@ -72,6 +73,7 @@
       allow_timing_details_(info.allow_timing_details),
       allow_redirect_details_(info.allow_redirect_details),
       allow_negative_value_(info.allow_negative_values),
+      is_secure_context_(is_secure_context),
       server_timing_(
           PerformanceServerTiming::FromParsedServerTiming(info.server_timing)) {
 }
@@ -255,16 +257,19 @@
 }
 
 DOMHighResTimeStamp PerformanceResourceTiming::secureConnectionStart() const {
-  if (!AllowTimingDetails())
+  if (!AllowTimingDetails() || !is_secure_context_)
     return 0.0;
-  ResourceLoadTiming* timing = GetResourceLoadTiming();
-  // Step 1 of
+
+  // Step 2 of
   // https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-secureconnectionstart.
   if (DidReuseConnection())
     return fetchStart();
-  // SslStart will be zero when a secure connection is not negotiated.
-  if (!timing || timing->SslStart().is_null())
+
+  ResourceLoadTiming* timing = GetResourceLoadTiming();
+  if (!timing || timing->SslStart().is_null()) {
+    // TODO(yoav): add DCHECK or use counter to make sure this never happens.
     return 0.0;
+  }
 
   return Performance::MonotonicTimeToDOMHighResTimeStamp(
       time_origin_, timing->SslStart(), allow_negative_value_);
diff --git a/third_party/blink/renderer/core/timing/performance_resource_timing.h b/third_party/blink/renderer/core/timing/performance_resource_timing.h
index 919c4167..21405a4 100644
--- a/third_party/blink/renderer/core/timing/performance_resource_timing.h
+++ b/third_party/blink/renderer/core/timing/performance_resource_timing.h
@@ -56,14 +56,15 @@
                             const WebVector<WebServerTimingInfo>&);
   PerformanceResourceTiming(const WebResourceTimingInfo&,
                             TimeTicks time_origin,
-                            const AtomicString& initiator_type);
+                            const AtomicString& initiator_type,
+                            bool is_secure_context);
   ~PerformanceResourceTiming() override;
-  static PerformanceResourceTiming* Create(
-      const WebResourceTimingInfo& info,
-      TimeTicks time_origin,
-      const AtomicString& initiator_type = g_null_atom) {
-    return MakeGarbageCollected<PerformanceResourceTiming>(info, time_origin,
-                                                           initiator_type);
+  static PerformanceResourceTiming* Create(const WebResourceTimingInfo& info,
+                                           TimeTicks time_origin,
+                                           const AtomicString& initiator_type,
+                                           bool is_secure_context) {
+    return MakeGarbageCollected<PerformanceResourceTiming>(
+        info, time_origin, initiator_type, is_secure_context);
   }
 
   AtomicString entryType() const override;
@@ -127,6 +128,7 @@
   bool allow_timing_details_;
   bool allow_redirect_details_;
   bool allow_negative_value_;
+  bool is_secure_context_ = false;
   HeapVector<Member<PerformanceServerTiming>> server_timing_;
 };
 
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_script_url.cc b/third_party/blink/renderer/core/trustedtypes/trusted_script_url.cc
index a1d527d..dd91ac5 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_script_url.cc
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_script_url.cc
@@ -4,14 +4,12 @@
 
 #include "third_party/blink/renderer/core/trustedtypes/trusted_script_url.h"
 
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
 namespace blink {
 
-TrustedScriptURL::TrustedScriptURL(const KURL& url) : url_(url) {}
+TrustedScriptURL::TrustedScriptURL(const String& url) : url_(url) {}
 
 String TrustedScriptURL::toString() const {
-  return url_.GetString();
+  return url_;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_script_url.h b/third_party/blink/renderer/core/trustedtypes/trusted_script_url.h
index 0ea47303..1dba541 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_script_url.h
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_script_url.h
@@ -7,13 +7,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-
-namespace WTF {
-
-class String;
-
-}  // namespace WTF
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
 
@@ -21,17 +15,17 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static TrustedScriptURL* Create(const KURL& url) {
+  static TrustedScriptURL* Create(const String& url) {
     return MakeGarbageCollected<TrustedScriptURL>(url);
   }
 
-  TrustedScriptURL(const KURL&);
+  TrustedScriptURL(const String& url);
 
   // TrustedScriptURL.idl
   String toString() const;
 
  private:
-  KURL url_;
+  const String url_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc
index 468f1ec..c439848 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc
@@ -113,7 +113,7 @@
     exception_state.RethrowV8Exception(try_catch.Exception());
     return nullptr;
   }
-  return TrustedScriptURL::Create(KURL(script_url));
+  return TrustedScriptURL::Create(script_url);
 }
 
 TrustedURL* TrustedTypePolicy::CreateURL(v8::Isolate* isolate,
@@ -132,7 +132,7 @@
     exception_state.RethrowV8Exception(try_catch.Exception());
     return nullptr;
   }
-  return TrustedURL::Create(KURL(url));
+  return TrustedURL::Create(url);
 }
 
 String TrustedTypePolicy::name() const {
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc
index 87f6764..eabed0a 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h"
 
+#include "third_party/blink/public/platform/web_feature.mojom-shared.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_trusted_html.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_trusted_script.h"
@@ -12,6 +13,7 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -24,6 +26,9 @@
     const TrustedTypePolicyOptions* policy_options,
     bool exposed,
     ExceptionState& exception_state) {
+  UseCounter::Count(GetExecutionContext(),
+                    WebFeature::kTrustedTypesCreatePolicy);
+
   if (!GetExecutionContext()
            ->GetContentSecurityPolicy()
            ->AllowTrustedTypePolicy(policy_name)) {
@@ -42,6 +47,10 @@
                                       "The default policy must be exposed.");
     return nullptr;
   }
+  if (policy_name == "default") {
+    UseCounter::Count(GetExecutionContext(),
+                      WebFeature::kTrustedTypesDefaultPolicyUsed);
+  }
   TrustedTypePolicy* policy = TrustedTypePolicy::Create(
       policy_name, const_cast<TrustedTypePolicyOptions*>(policy_options),
       exposed);
@@ -59,7 +68,9 @@
 }
 
 TrustedTypePolicyFactory::TrustedTypePolicyFactory(ExecutionContext* context)
-    : ContextClient(context) {}
+    : ContextClient(context) {
+  UseCounter::Count(context, WebFeature::kTrustedTypesEnabled);
+}
 
 Vector<String> TrustedTypePolicyFactory::getPolicyNames() const {
   Vector<String> policyNames;
@@ -113,6 +124,14 @@
          wrapper_type_info->Equals(V8TrustedURL::GetWrapperTypeInfo());
 }
 
+void TrustedTypePolicyFactory::CountTrustedTypeAssignmentError() {
+  if (!hadAssignmentError) {
+    UseCounter::Count(GetExecutionContext(),
+                      WebFeature::kTrustedTypesAssignmentError);
+    hadAssignmentError = true;
+  }
+}
+
 void TrustedTypePolicyFactory::Trace(blink::Visitor* visitor) {
   ScriptWrappable::Trace(visitor);
   ContextClient::Trace(visitor);
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
index 54b9689..c103e7d 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
@@ -46,6 +46,11 @@
   bool isScriptURL(ScriptState*, const ScriptValue&);
   bool isURL(ScriptState*, const ScriptValue&);
 
+  // Count whether a Trusted Type error occured during DOM operations.
+  // (We aggregate this here to get a count per document, so that we can
+  //  relate it to the total number of TT enabled documents.)
+  void CountTrustedTypeAssignmentError();
+
   void Trace(blink::Visitor*) override;
 
  private:
@@ -53,6 +58,8 @@
                                                            const ScriptValue&);
 
   HeapHashMap<String, Member<TrustedTypePolicy>> policy_map_;
+
+  bool hadAssignmentError = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc b/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
index 83cbee3..ccec93a4 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
@@ -33,6 +33,11 @@
   if (string_or_trusted_type.IsString() && doc && doc->RequireTrustedTypes()) {
     exception_state.ThrowTypeError(
         "This document requires a Trusted Type assignment.");
+
+    // Test case docs (Document::CreateForTest) might not have a window.
+    if (doc->ExecutingWindow())
+      doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
+
     return g_empty_string;
   }
 
@@ -86,6 +91,7 @@
   if (!default_policy) {
     exception_state.ThrowTypeError(
         "This document requires `TrustedHTML` assignment.");
+    doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
     return g_empty_string;
   }
 
@@ -96,6 +102,7 @@
     exception_state.ThrowTypeError(
         "This document requires `TrustedHTML` assignment and 'default' policy "
         "failed to execute.");
+    doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
     return g_empty_string;
   }
 
@@ -138,6 +145,7 @@
   if (!default_policy) {
     exception_state.ThrowTypeError(
         "This document requires `TrustedScript` assignment.");
+    doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
     return g_empty_string;
   }
 
@@ -154,6 +162,7 @@
         "This document requires `TrustedScript` assignment and 'default' "
         "policy "
         "failed to execute.");
+    doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
     return g_empty_string;
   }
 
@@ -182,6 +191,7 @@
   if (!default_policy) {
     exception_state.ThrowTypeError(
         "This document requires `TrustedScriptURL` assignment.");
+    doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
     return g_empty_string;
   }
 
@@ -195,6 +205,7 @@
         "This document requires `TrustedScriptURL` assignment and 'default' "
         "policy "
         "failed to execute.");
+    doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
     return g_empty_string;
   }
 
@@ -222,6 +233,7 @@
   if (!default_policy) {
     exception_state.ThrowTypeError(
         "This document requires `TrustedURL` assignment.");
+    doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
     return g_empty_string;
   }
 
@@ -233,6 +245,7 @@
     exception_state.ThrowTypeError(
         "This document requires `TrustedURL` assignment and 'default' policy "
         "failed to execute.");
+    doc->ExecutingWindow()->trustedTypes()->CountTrustedTypeAssignmentError();
     return g_empty_string;
   }
 
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc b/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc
index f17780d..aa97005 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc
@@ -189,7 +189,7 @@
 }
 
 TEST(TrustedTypesUtilTest, GetStringFromTrustedType_TrustedScriptURL) {
-  KURL url_address("http://www.example.com/");
+  String url_address = "http://www.example.com/";
   TrustedScriptURL* script_url = TrustedScriptURL::Create(url_address);
   StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL
       trusted_value =
@@ -198,8 +198,18 @@
   GetStringFromTrustedTypeWorks(trusted_value, "http://www.example.com/");
 }
 
+TEST(TrustedTypesUtilTest, GetStringFromTrustedType_TrustedScriptURL_Relative) {
+  String url_address = "relative/url.html";
+  TrustedScriptURL* script_url = TrustedScriptURL::Create(url_address);
+  StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL
+      trusted_value =
+          StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL::
+              FromTrustedScriptURL(script_url);
+  GetStringFromTrustedTypeWorks(trusted_value, "relative/url.html");
+}
+
 TEST(TrustedTypesUtilTest, GetStringFromTrustedType_TrustedURL) {
-  KURL url_address("http://www.example.com/");
+  String url_address = "http://www.example.com/";
   TrustedURL* url = TrustedURL::Create(url_address);
   StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL
       trusted_value =
@@ -208,6 +218,16 @@
   GetStringFromTrustedTypeWorks(trusted_value, "http://www.example.com/");
 }
 
+TEST(TrustedTypesUtilTest, GetStringFromTrustedType_TrustedURL_Relative) {
+  String url_address = "relative/url.html";
+  TrustedURL* url = TrustedURL::Create(url_address);
+  StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL
+      trusted_value =
+          StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL::
+              FromTrustedURL(url);
+  GetStringFromTrustedTypeWorks(trusted_value, "relative/url.html");
+}
+
 TEST(TrustedTypesUtilTest, GetStringFromTrustedType_String) {
   StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL
       string_value =
@@ -239,7 +259,7 @@
 
 TEST(TrustedTypesUtilTest,
      GetStringFromTrustedTypeWithoutCheck_TrustedScriptURL) {
-  KURL url_address("http://www.example.com/");
+  String url_address = "http://www.example.com/";
   TrustedScriptURL* script_url = TrustedScriptURL::Create(url_address);
   StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL
       trusted_value =
@@ -250,7 +270,7 @@
 }
 
 TEST(TrustedTypesUtilTest, GetStringFromTrustedTypeWithoutCheck_TrustedURL) {
-  KURL url_address("http://www.example.com/");
+  String url_address = "http://www.example.com/";
   TrustedURL* url = TrustedURL::Create(url_address);
   StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL
       trusted_value =
@@ -306,7 +326,7 @@
 
 // GetStringFromTrustedScriptURL tests
 TEST(TrustedTypesUtilTest, GetStringFromTrustedScriptURL_TrustedScriptURL) {
-  KURL url_address("http://www.example.com/");
+  String url_address = "http://www.example.com/";
   TrustedScriptURL* script_url = TrustedScriptURL::Create(url_address);
   StringOrTrustedScriptURL trusted_value =
       StringOrTrustedScriptURL::FromTrustedScriptURL(script_url);
@@ -321,7 +341,7 @@
 
 // GetStringFromTrustedURL tests
 TEST(TrustedTypesUtilTest, GetStringFromTrustedURL_TrustedURL) {
-  KURL url_address("http://www.example.com/");
+  String url_address = "http://www.example.com/";
   TrustedURL* url = TrustedURL::Create(url_address);
   USVStringOrTrustedURL trusted_value =
       USVStringOrTrustedURL::FromTrustedURL(url);
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_url.cc b/third_party/blink/renderer/core/trustedtypes/trusted_url.cc
index 0093775b..b8b46e3 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_url.cc
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_url.cc
@@ -4,14 +4,12 @@
 
 #include "third_party/blink/renderer/core/trustedtypes/trusted_url.h"
 
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
 namespace blink {
 
-TrustedURL::TrustedURL(const KURL& url) : url_(url) {}
+TrustedURL::TrustedURL(const String& url) : url_(url) {}
 
 String TrustedURL::toString() const {
-  return url_.GetString();
+  return url_;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_url.h b/third_party/blink/renderer/core/trustedtypes/trusted_url.h
index df18273a..d2f8ee2 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_url.h
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_url.h
@@ -7,13 +7,7 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-
-namespace WTF {
-
-class String;
-
-}  // namespace WTF
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
 
@@ -21,17 +15,17 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static TrustedURL* Create(const KURL& url) {
+  static TrustedURL* Create(const String& url) {
     return MakeGarbageCollected<TrustedURL>(url);
   }
 
-  TrustedURL(const KURL&);
+  TrustedURL(const String& url);
 
   // TrustedURL.idl
   String toString() const;
 
  private:
-  KURL url_;
+  const String url_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
index c56a9567..5c48f407 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h"
 
+#include "base/metrics/histogram_macros.h"
 #include "base/optional.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h"
@@ -198,6 +199,12 @@
     mojom::blink::QueryParamsPtr cache_query_params,
     ExceptionState& exception_state,
     bool match_all) {
+  DCHECK(script_state);
+  UMA_HISTOGRAM_BOOLEAN("BackgroundFetch.MatchCalledFromDocumentScope",
+                        ExecutionContext::From(script_state)->IsDocument());
+  UMA_HISTOGRAM_BOOLEAN("BackgroundFetch.MatchCalledWhenFetchIsIncomplete",
+                        result_ == mojom::BackgroundFetchResult::UNSET);
+
   if (!records_available_) {
     return ScriptPromise::RejectWithDOMException(
         script_state,
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc
index 66343f40..840482e 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc
@@ -131,8 +131,8 @@
 void QuicTransportProxy::OnConnectionFailed(const std::string& error_details,
                                             bool from_remote) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  delegate_->OnConnectionFailed(error_details, from_remote);
   stream_proxies_.clear();
+  delegate_->OnConnectionFailed(error_details, from_remote);
 }
 
 void QuicTransportProxy::OnStream(
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
index 6d9dd135..750ce32b7 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
@@ -249,6 +249,13 @@
 
 void RTCQuicTransport::stop() {
   if (IsClosed()) {
+    // The transport could have already been closed due to the context being
+    // destroyed, the RTCIceTransport closing or a remote/local stop().
+    return;
+  }
+  if (IsDisposed()) {
+    // This occurs in the "failed" state.
+    state_ = RTCQuicTransportState::kClosed;
     return;
   }
   Close(CloseReason::kLocalStopped);
@@ -310,7 +317,7 @@
 }
 
 void RTCQuicTransport::Close(CloseReason reason) {
-  DCHECK(!IsClosed());
+  DCHECK(!IsDisposed());
 
   // Disconnect from the RTCIceTransport, allowing a new RTCQuicTransport to
   // connect to it.
@@ -348,7 +355,7 @@
   }
 
   DCHECK(!proxy_);
-  DCHECK(IsClosed());
+  DCHECK(IsDisposed());
 }
 
 bool RTCQuicTransport::RaiseExceptionIfClosed(
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h
index c69f9e7..21c2bb14 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h
@@ -120,6 +120,12 @@
   void Close(CloseReason reason);
 
   bool IsClosed() const { return state_ == RTCQuicTransportState::kClosed; }
+  // The transport is no longer usable once it has reached the "failed" or
+  // "closed" state.
+  bool IsDisposed() const {
+    return (state_ == RTCQuicTransportState::kClosed ||
+            state_ == RTCQuicTransportState::kFailed);
+  }
   bool RaiseExceptionIfClosed(ExceptionState& exception_state) const;
 
   Member<RTCIceTransport> transport_;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc
index 5c2df98..2c62b29 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc
@@ -242,6 +242,45 @@
   EXPECT_TRUE(mock_deleted);
 }
 
+// Test that the P2PQuicTransport is deleted and the RTCQuicTransport goes to
+// the "failed" state when the QUIC connection fails.
+TEST_F(RTCQuicTransportTest,
+       ConnectionFailedBecomesClosedAndDeletesP2PQuicTransport) {
+  V8TestingScope scope;
+
+  bool mock_deleted = false;
+  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
+  EXPECT_CALL(*mock_transport, Die()).WillOnce(Assign(&mock_deleted, true));
+
+  P2PQuicTransport::Delegate* delegate = nullptr;
+  Persistent<RTCQuicTransport> quic_transport =
+      CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate);
+  DCHECK(delegate);
+  delegate->OnConnectionFailed("test_failure", /*from_remote=*/false);
+  RunUntilIdle();
+
+  EXPECT_TRUE(mock_deleted);
+  EXPECT_EQ("failed", quic_transport->state());
+}
+
+// Test that after the connection fails, stop() will change the state
+// of the transport to "closed".
+TEST_F(RTCQuicTransportTest, StopAfterConnectionFailed) {
+  V8TestingScope scope;
+
+  P2PQuicTransport::Delegate* delegate = nullptr;
+  Persistent<RTCQuicTransport> quic_transport = CreateConnectedQuicTransport(
+      scope, std::make_unique<MockP2PQuicTransport>(), &delegate);
+  DCHECK(delegate);
+  delegate->OnConnectionFailed("test_failure", /*from_remote=*/false);
+  RunUntilIdle();
+
+  EXPECT_EQ("failed", quic_transport->state());
+
+  quic_transport->stop();
+  EXPECT_EQ("closed", quic_transport->state());
+}
+
 // Test that the P2PQuicTransport is deleted when the underlying RTCIceTransport
 // is ContextDestroyed.
 TEST_F(RTCQuicTransportTest,
diff --git a/third_party/blink/renderer/platform/heap/heap_compact.cc b/third_party/blink/renderer/platform/heap/heap_compact.cc
index 6e3559e4..055f2dc 100644
--- a/third_party/blink/renderer/platform/heap/heap_compact.cc
+++ b/third_party/blink/renderer/platform/heap/heap_compact.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/debug/alias.h"
 #include "base/memory/ptr_util.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h"
@@ -191,6 +192,16 @@
     DCHECK(relocatable_pages_.Contains(from_page));
 #endif
 
+    // TODO(keishi): Code to determine if crash is related to interior fixups.
+    // Remove when finished. crbug.com/918064
+    enum DebugSlotType {
+      kNormalSlot,
+      kInteriorSlotPreMove,
+      kInteriorSlotPostMove,
+    };
+    DebugSlotType slot_type = kNormalSlot;
+    base::debug::Alias(&slot_type);
+
     // If the object is referenced by a slot that is contained on a compacted
     // area itself, check whether it can be updated already.
     MovableReference* slot = reinterpret_cast<MovableReference*>(it->value);
@@ -200,10 +211,12 @@
           reinterpret_cast<MovableReference*>(interior->value);
       if (!slot_location) {
         interior_fixups_.Set(slot, to);
+        slot_type = kInteriorSlotPreMove;
       } else {
         LOG_HEAP_COMPACTION()
             << "Redirected slot: " << slot << " => " << slot_location;
         slot = slot_location;
+        slot_type = kInteriorSlotPostMove;
       }
     }
 
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index b179b4b..3070c65 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -596,6 +596,7 @@
     // https://crbug.com/766694 for testing disabling the feature.
     {
       name: "HTMLImports",
+      origin_trial_feature_name: "WebComponentsV0",
       status: "stable",
     },
     // https://crbug.com/523952 for testing disabling the feature.
diff --git a/third_party/blink/web_tests/LeakExpectations b/third_party/blink/web_tests/LeakExpectations
index 92b18ee..1be9498 100644
--- a/third_party/blink/web_tests/LeakExpectations
+++ b/third_party/blink/web_tests/LeakExpectations
@@ -97,6 +97,9 @@
 
 # Sheriff 2019-01-04
 crbug.com/919117 [ Linux ] virtual/mouseevent_fractional/fast/events/middleClickAutoscroll-drag.html [ Pass Leak ]
+
+# Sheriff 2019-01-07
+crbug.com/919497 [ Linux ] virtual/threaded/http/tests/devtools/tracing/timeline-gpu-tasks.js [ Pass Leak ]
 ###########################################################################
 # WARNING: Memory leaks must be fixed asap. Sheriff is expected to revert #
 # culprit CLs instead of suppressing the leaks. If you have any question, #
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index ac5749c..a0b87d7 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -2198,3 +2198,4 @@
 external/wpt/css/css-overscroll-behavior/overscrollBehavior-manual.html [ WontFix ]
 external/wpt/html/semantics/forms/the-input-element/event-select-manual.html [ WontFix ]
 external/wpt/html/editing/dnd/the-datatransferitem-interface/getAsString-manual.html [ WontFix ]
+external/wpt/payment-request/billing-address-changed-manual.https.html [ WontFix ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 65df4c4..cc5a92e 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -633,11 +633,6 @@
 crbug.com/885175 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/grid-abspos-staticpos-justify-self-vertWM-003.html [ Failure ]
 crbug.com/885175 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/grid-abspos-staticpos-justify-self-vertWM-004.html [ Failure ]
 
-crbug.com/855009 external/wpt/workers/semantics/structured-clone/dedicated.html [ Skip ]
-crbug.com/855009 external/wpt/workers/semantics/structured-clone/shared.html [ Skip ]
-crbug.com/855009 virtual/omt-worker-fetch/external/wpt/workers/semantics/structured-clone/dedicated.html [ Skip ]
-crbug.com/855009 virtual/omt-worker-fetch/external/wpt/workers/semantics/structured-clone/shared.html [ Skip ]
-
 # ====== Layout team owned tests to here ======
 
 # ====== LayoutNG-only failures from here ======
@@ -5915,7 +5910,7 @@
 #Sheriff 2018-11-14
 crbug.com/905694 [ Linux ] virtual/threaded/fast/scroll-behavior/smooth-scroll/scroll-during-selection.html [ Failure Pass Crash ]
 crbug.com/905772 [ Linux ] virtual/sampling-heap-profiler/inspector-protocol/memory/sampling-native-profile-partition-alloc.js [ Failure Pass ]
-crbug.com/905827 [ Mac10.13 ] fast/dom/StyleSheet/stylesheet-move-between-documents-crash.html [ Failure Pass Crash ]
+crbug.com/905827 fast/dom/StyleSheet/stylesheet-move-between-documents-crash.html [ Skip ]
 
 # Flaky crash due to "bad mojo message".
 crbug.com/906952 editing/pasteboard/file-drag-to-editable.html [ Pass Crash ]
@@ -5997,6 +5992,8 @@
 crbug.com/v8/8319 external/wpt/wasm/jsapi/global/value-get-set.any.html [ Pass Failure ]
 crbug.com/v8/8319 external/wpt/wasm/jsapi/global/value-get-set.any.worker.html [ Pass Failure ]
 
+crbug.com/919272 external/wpt/resource-timing/resource-timing.html [ Skip ]
+
 # ssauleau 2018-12-20
 crbug.com/v8/8319 external/wpt/wasm/jsapi/table/get-set.any.html [ Pass Failure ]
 crbug.com/v8/8319 external/wpt/wasm/jsapi/table/get-set.any.worker.html [ Pass Failure ]
@@ -6010,9 +6007,11 @@
 
 # Sheriff 2018-12-27
 crbug.com/917970 [ Mac10.13 Retina ] virtual/mouseevent_fractional/fast/events/popup-blocking-timers5.html [ Pass Failure ]
+crbug.com/917970 [ Mac10.13 Retina ] virtual/user-activation-v2/fast/events/popup-blocking-timers5.html [ Pass Failure ]
 
 # Sheriff 2019-01-03
 crbug.com/918905 [ Mac Linux ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/block-size-with-min-or-max-content-table-1b.html [ Pass Failure ]
 
-# Sheriff 2019-01-04
-crbug.com/919096 [ Linux ] virtual/display-lock/display-lock/lock-before-append/measure-updated-layout.html [ Timeout Pass ]
+# Sheriff 2019-01-07
+crbug.com/919492 [ Mac ] virtual/fractional_scrolling_threaded/fast/scrolling/overflow-scrollability.html [ Timeout Pass ]
+crbug.com/919504 paint/invalidation/window-resize/window-resize-vertical-writing-mode.html [ Timeout Pass ]
diff --git a/third_party/blink/web_tests/display-lock/lock-before-append/measure-forced-layout.html b/third_party/blink/web_tests/display-lock/lock-before-append/measure-forced-layout.html
index ef6cb4e3..ce86774 100644
--- a/third_party/blink/web_tests/display-lock/lock-before-append/measure-forced-layout.html
+++ b/third_party/blink/web_tests/display-lock/lock-before-append/measure-forced-layout.html
@@ -86,7 +86,9 @@
     });
   }
 
-  runTest();
+  window.onload = function() {
+    requestAnimationFrame(() => requestAnimationFrame(runTest));
+  };
 }, "Measure Forced Layout");
 </script>
 
diff --git a/third_party/blink/web_tests/display-lock/lock-before-append/measure-updated-layout.html b/third_party/blink/web_tests/display-lock/lock-before-append/measure-updated-layout.html
index e5c2c7b..f4c97a3a 100644
--- a/third_party/blink/web_tests/display-lock/lock-before-append/measure-updated-layout.html
+++ b/third_party/blink/web_tests/display-lock/lock-before-append/measure-updated-layout.html
@@ -88,7 +88,9 @@
     });
   }
 
-  runTest();
+  window.onload = function() {
+    requestAnimationFrame(() => requestAnimationFrame(runTest));
+  };
 }, "Measure Updated Layout");
 </script>
 
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
index 6571860..7fec1dd1 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -5491,6 +5491,12 @@
      {}
     ]
    ],
+   "payment-request/billing-address-changed-manual.https.html": [
+    [
+     "/payment-request/billing-address-changed-manual.https.html",
+     {}
+    ]
+   ],
    "payment-request/change-shipping-option-manual.https.html": [
     [
      "/payment-request/change-shipping-option-manual.https.html",
@@ -47137,6 +47143,18 @@
      {}
     ]
    ],
+   "css/css-grid/grid-definition/grid-auto-repeat-multiple-values-001.html": [
+    [
+     "/css/css-grid/grid-definition/grid-auto-repeat-multiple-values-001.html",
+     [
+      [
+       "/css/css-grid/reference/grid-auto-repeat-multiple-values-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-grid/grid-definition/grid-layout-auto-tracks.html": [
     [
      "/css/css-grid/grid-definition/grid-layout-auto-tracks.html",
@@ -136994,6 +137012,11 @@
      {}
     ]
    ],
+   "css/css-grid/reference/grid-auto-repeat-multiple-values-001-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-grid/reference/grid-different-gutters-ref.html": [
     [
      {}
@@ -190129,16 +190152,6 @@
      {}
     ]
    ],
-   "workers/semantics/structured-clone/dedicated-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "workers/semantics/structured-clone/shared-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "workers/semantics/xhr/001-1.xml": [
     [
      {}
@@ -272036,6 +272049,12 @@
      {}
     ]
    ],
+   "resource-timing/test_resource_timing.https.html": [
+    [
+     "/resource-timing/test_resource_timing.https.html",
+     {}
+    ]
+   ],
    "screen-capture/getdisplaymedia.https.html": [
     [
      "/screen-capture/getdisplaymedia.https.html",
@@ -343733,6 +343752,10 @@
    "00ef5a5974423967dadf26a594539ab2eb65526c",
    "reftest"
   ],
+  "css/css-grid/grid-definition/grid-auto-repeat-multiple-values-001.html": [
+   "085d94996f1142d11f9f9c6076e6d9afc025c39c",
+   "reftest"
+  ],
   "css/css-grid/grid-definition/grid-change-fit-content-argument-001.html": [
    "9441b0a439e1bbdcd3954af439a49ac162a513a1",
    "testharness"
@@ -344693,6 +344716,10 @@
    "1f325f37a2cd0bc08603ed3b3fd2730e4084203a",
    "support"
   ],
+  "css/css-grid/reference/grid-auto-repeat-multiple-values-001-ref.html": [
+   "0b8ef6d39bf6f01d994f6025f34c0136cc2908cf",
+   "support"
+  ],
   "css/css-grid/reference/grid-different-gutters-ref.html": [
    "57d27ff3aaea88eaeeed6f34f8ac49623b409fd2",
    "support"
@@ -426273,6 +426300,10 @@
    "4564d264c4e2c542b25740e92709c9e7c0a14a1d",
    "testharness"
   ],
+  "payment-request/billing-address-changed-manual.https.html": [
+   "cb9acf6eb6a20df5ddd03ef734796cefb6195467",
+   "manual"
+  ],
   "payment-request/change-shipping-option-manual.https.html": [
    "a33365bac73ed51b6873215d0f54d79a73422163",
    "manual"
@@ -437481,8 +437512,12 @@
    "f4e851abb203aca49194aef51646be673507078f",
    "testharness"
   ],
+  "resource-timing/test_resource_timing.https.html": [
+   "f4e851abb203aca49194aef51646be673507078f",
+   "testharness"
+  ],
   "resource-timing/test_resource_timing.js": [
-   "8e729e013567a123f9c4a71ab7ea30435b7e2b47",
+   "598a727bf88e7f47556d509f6929a86b64b0506c",
    "support"
   ],
   "resources/.gitignore": [
@@ -445034,7 +445069,7 @@
    "testharness"
   ],
   "trusted-types/TrustedTypePolicy-createXXX.tentative.html": [
-   "6a0151ad9bcf7d02b6a98532ba53db509e086f83",
+   "475a264790482aedf714958f63a4d47d69661941",
    "testharness"
   ],
   "trusted-types/TrustedTypePolicy-exposed.tentative.html": [
@@ -445046,7 +445081,7 @@
    "testharness"
   ],
   "trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html": [
-   "a162d84cd820051d6c5868c35b58cd347b0026e5",
+   "37e245ee27aa5828bd97568d9390d9cbfbb6f968",
    "testharness"
   ],
   "trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-noNamesGiven.tentative.html": [
@@ -445122,7 +445157,7 @@
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html": [
-   "b24ab69c0671dd3e8551f289e1cb67e455e1937c",
+   "c243757887a83611d28c61c1c1ce45a0fda925b2",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-Element-setAttributeNS.tentative.html": [
@@ -445134,7 +445169,7 @@
    "support"
   ],
   "trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html": [
-   "0eef00bd7772b50bd6d774425cbe688eacf0183f",
+   "4a5c2cc8d62e22888b463b724bab255500943af5",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-Location-assign.tentative.html": [
@@ -455861,18 +455896,10 @@
    "8c2f07ee7305a7a6d83e3c2cd8aaf4367fac35ab",
    "testharness"
   ],
-  "workers/semantics/structured-clone/dedicated-expected.txt": [
-   "3c8beb85ecc7021b57ebbfb99e100db89c633a32",
-   "support"
-  ],
   "workers/semantics/structured-clone/dedicated.html": [
    "2f1732c13b3d330f2176dc9f45a552fb506d514e",
    "testharness"
   ],
-  "workers/semantics/structured-clone/shared-expected.txt": [
-   "3c8beb85ecc7021b57ebbfb99e100db89c633a32",
-   "support"
-  ],
   "workers/semantics/structured-clone/shared.html": [
    "793da8ff3a754454066a28d5c514d4e7f9d8a86a",
    "testharness"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-multiple-values-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-multiple-values-001.html
new file mode 100644
index 0000000..085d9499
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-multiple-values-001.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <title>CSS Grid Layout Test: Auto Repaeat with Multiple Tracks and Gutters</title>
+    <link rel="author" title="Yu Shen" href="shenyu.tcv@gmail.com">
+    <link rel="help" href="https://www.w3.org/TR/css-grid-1/#repeat-notation">
+    <link rel="match" href="../reference/grid-auto-repeat-multiple-values-001-ref.html">
+    <style>
+        .grid-container {
+            display: grid;
+            border: solid thick;
+            margin: 10px;
+        }
+
+        .columns {
+            grid-template-columns: repeat(auto-fill, 50px 50px);
+            grid-auto-rows: 25px;
+            grid-column-gap: 100px;
+            width: 300px;
+        }
+
+        .rows {
+            grid-auto-flow: column;
+            grid-template-rows: repeat(auto-fill, 50px 50px);
+            grid-auto-columns: 25px;
+            grid-row-gap: 100px;
+            width: min-content;
+            height: 300px;
+        }
+
+        .grid-container>div {
+            background: lime;
+        }
+    </style>
+</head>
+
+<body>
+    <p>The test passes if it has the same visual effect as reference.</p>
+    <div class="grid-container columns">
+        <div></div>
+        <div></div>
+        <div></div>
+        <div></div>
+    </div>
+    <div class="grid-container rows">
+        <div></div>
+        <div></div>
+        <div></div>
+        <div></div>
+    </div>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/reference/grid-auto-repeat-multiple-values-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/reference/grid-auto-repeat-multiple-values-001-ref.html
new file mode 100644
index 0000000..0b8ef6d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/reference/grid-auto-repeat-multiple-values-001-ref.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <title>CSS Grid Layout Test: Auto Repaeat with Multiple Tracks and Gutters</title>
+    <link rel="author" title="Yu Shen" href="shenyu.tcv@gmail.com">
+    <style>
+        .match-container {
+            border: solid thick black;
+            position: relative;
+            margin: 10px;
+        }
+
+        .column {
+            width: 300px;
+        }
+
+        .row {
+            width: min-content;
+            height: 300px;
+        }
+
+        .item {
+            background: lime;
+            width: 50px;
+            height: 50px;
+        }
+
+        .column-second {
+            position: absolute;
+            top: 0;
+            left: 150px;
+        }
+
+        .row-second {
+            position: absolute;
+            top: 150px;
+            left: 0px;
+        }
+    </style>
+</head>
+
+<body>
+    <p>The test passes if it has the same visual effect as reference.</p>
+    <div class="match-container column">
+        <div class="item"></div>
+        <div class="item column-second"></div>
+    </div>
+    <div class="match-container row">
+        <div class="item"></div>
+        <div class="item row-second"></div>
+    </div>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/billing-address-changed-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/billing-address-changed-manual.https.html
new file mode 100644
index 0000000..cb9acf6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/payment-request/billing-address-changed-manual.https.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html> <meta charset="utf-8" />
+<title>Test for requesting billing address</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+  setup({
+    explicit_done: true,
+    explicit_timeout: true,
+  });
+
+  const methods = [
+    { supportedMethods: "basic-card" },
+    { supportedMethods: "https://apple.com/apple-pay" },
+  ];
+
+  const details = {
+    total: {
+      label: "label",
+      amount: { currency: "USD", value: "5.00" },
+    },
+  };
+  test(() => {
+    assert_true(
+      "onpaymentmethodchange" in PaymentRequest.prototype,
+      "The paymentmethodchange is not supported"
+    );
+  }, "onpaymentmethodchange is in prototype");
+
+  function dontRequestBillingAddress() {
+    promise_test(async t => {
+      const request = new PaymentRequest(methods, details, {});
+      const showPromise = request.show();
+
+      // Let's check the method data from event.
+      const { methodDetails } = await new Promise(resolve =>
+        request.addEventListener("paymentmethodchange", resolve)
+      );
+
+      assert_true("billingAddress" in methodDetails);
+      assert_equals(
+        methodDetails.billingAddress,
+        null,
+        "Expected methodDetails.billingAddress to be null"
+      );
+      await request.abort();
+    });
+  }
+
+  function requestBillingAddress() {
+    promise_test(async t => {
+      const request = new PaymentRequest(methods, details, {
+        requestBillingAddress: true,
+      });
+      const showPromise = request.show();
+
+      // Let's check the method data from event.
+      const { methodDetails } = await new Promise(resolve =>
+        request.addEventListener("paymentmethodchange", resolve)
+      );
+
+      assert_true("billingAddress" in methodDetails);
+
+      const { billingAddress } = methodDetails;
+      assert_true(
+        billingAddress instanceof PaymentAddress,
+        "Expected instance of PaymentAddress"
+      );
+      await request.abort();
+    });
+  }
+</script>
+
+<h2>Request billing address</h2>
+<p>
+  Click on each button in sequence from top to bottom without refreshing the
+  page. Each button will bring up the Payment Request UI window.
+</p>
+<p>
+  When the payment sheet is presented, select a payment method (e.g., a credit
+  card).
+</p>
+<ol>
+  <li>
+    <button onclick="dontRequestBillingAddress()">
+      When no billing address is requested,
+      `PaymentMethodChangeEvent.methodDetails.billingAddress` is null.
+    </button>
+  </li>
+  <li>
+    <button onclick="requestBillingAddress()">
+      When billing address is
+      requested,`PaymentMethodChangeEvent.methodDetails.billingAddress` is a
+      `PaymentAddress`.
+    </button>
+  </li>
+  <li><button onclick="done()">Done!</button></li>
+</ol>
+<small>
+  If you find a buggy test, please
+  <a href="https://github.com/web-platform-tests/wpt/issues">file a bug</a> and
+  tag one of the
+  <a
+    href="https://github.com/web-platform-tests/wpt/blob/master/payment-request/META.yml"
+    >suggested reviewers</a
+  >.
+</small>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resource_connection_reuse.html b/third_party/blink/web_tests/external/wpt/resource-timing/resource_connection_reuse.html
index 74c7c1082..7a31a7e1 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/resource_connection_reuse.html
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resource_connection_reuse.html
@@ -21,7 +21,6 @@
 function setup_iframe() {
     iframe = document.getElementById('frameContext');
     d = iframe.contentWindow.document;
-    iframeBody = d.body;
     iframe.addEventListener('load', onload_test, false);
 }
 
@@ -41,10 +40,11 @@
         const entry = entries[1];
         test_equals(entry.fetchStart, entry.connectStart, 'connectStart and fetchStart should be the same');
         test_equals(entry.fetchStart, entry.connectEnd, 'connectEnd and fetchStart should be the same');
-        test_equals(entry.fetchStart, entry.secureConnectionStart, 'secureConnectStart and fetchStart should be the same');
+        if(!window.isSecureConnection) {
+            test_equals(entry.secureConnectionStart, 0, 'secureConnectStart should be zero');
+        }
         test_equals(entry.fetchStart, entry.domainLookupStart, 'domainLookupStart and fetchStart should be the same')
         test_equals(entry.fetchStart, entry.domainLookupEnd, 'domainLookupEnd and fetchStart should be the same')
-
     }
 
     done();
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resource_connection_reuse.https.html b/third_party/blink/web_tests/external/wpt/resource-timing/resource_connection_reuse.https.html
new file mode 100644
index 0000000..bc79a851
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resource_connection_reuse.https.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing connection reuse</title>
+<link rel="author" title="Google" href="http://www.google.com/" />
+<link rel="help" href="https://www.w3.org/TR/resource-timing/#dom-performanceresourcetiming-initiatortype"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webperftestharness.js"></script>
+<script src="resources/webperftestharnessextension.js"></script>
+<script>
+setup({explicit_done: true});
+let iframe;
+let d;
+let body;
+
+// Explicitly test the namespace before we start testing.
+test_namespace('getEntriesByType');
+
+function setup_iframe() {
+    iframe = document.getElementById('frameContext');
+    d = iframe.contentWindow.document;
+    iframe.addEventListener('load', onload_test, false);
+}
+
+function onload_test() {
+    if (window.performance.getEntriesByType === undefined) {
+      done();
+      return;
+    }
+    const context = new PerformanceContext(iframe.contentWindow.performance);
+    const entries = context.getEntriesByType('resource');
+
+    // When a persistent connection is used, follow-on resources should be included as PerformanceResourceTiming objects.
+    test_equals(entries.length, 2, 'There should be 2 PerformanceEntries');
+
+    if (entries.length >= 2) {
+        // When a persistent connection is used, for the resource that reuses the socket, connectStart and connectEnd should have the same value as fetchStart.
+        const entry = entries[1];
+        test_equals(entry.fetchStart, entry.connectStart, 'connectStart and fetchStart should be the same');
+        test_equals(entry.fetchStart, entry.connectEnd, 'connectEnd and fetchStart should be the same');
+        test_equals(entry.fetchStart, entry.secureConnectionStart, 'secureConnectStart and fetchStart should be the same');
+        test_equals(entry.fetchStart, entry.domainLookupStart, 'domainLookupStart and fetchStart should be the same')
+        test_equals(entry.fetchStart, entry.domainLookupEnd, 'domainLookupEnd and fetchStart should be the same')
+    }
+
+    done();
+}
+
+window.setup_iframe = setup_iframe;
+</script>
+</head>
+<body>
+<h1>Description</h1>
+<p>This test validates that connectStart and connectEnd are the same when a connection is reused (e.g. when a persistent connection is used).</p>
+<div id="log"></div>
+<iframe id="frameContext" src="resources/fake_responses.html"></iframe>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/test_resource_timing.https.html b/third_party/blink/web_tests/external/wpt/resource-timing/test_resource_timing.https.html
new file mode 100644
index 0000000..f4e851a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/test_resource_timing.https.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="UTF-8" />
+        <title>window.performance Resource Timing Entries exist</title>
+        <link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
+        <link rel="help" href="https://w3c.github.io/web-performance/specs/ResourceTiming/Overview.html"/>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="test_resource_timing.js"></script>
+    </head>
+    <body>
+        <h1>Description</h1>
+        <p>
+           NOTE: Due to caching behavior in the browser, it is possible that when revisiting this page, some resources
+           may not have to be fetched from the network.  As a result, the performance timeline will not contain entries
+           for these resources. This test will fail if any entries are missing to ensure that all resources are fetched
+           from the network and entries for these resources exist in the Performance Timeline.  If revisiting this page,
+           please either perform a full reload of the page or clear the cache between visits.
+        </p>
+
+        <div id="log"></div>
+    </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/test_resource_timing.js b/third_party/blink/web_tests/external/wpt/resource-timing/test_resource_timing.js
index 8e729e01..598a727 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/test_resource_timing.js
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/test_resource_timing.js
@@ -186,22 +186,21 @@
         const entries = window.performance.getEntriesByName(expected.name);
         assert_equals(entries.length, 1, 'There should be a single matching entry');
         const actual = entries[0];
-
-        // Debugging bug 1263428
-        // Feel free to remove/overwrite this piece of code
-        if (actual.connectStart < actual.domainLookupEnd) {
-            assert_true(false, "actual: "+JSON.stringify(actual));
+        if (window.location.protocol == "http:") {
+            assert_equals(actual.secureConnectionStart, 0, 'secureConnectionStart should be 0 in http');
+        } else {
+            assert_greater_than(actual.secureConnectionStart, 0, 'secureConnectionStart should not be 0 in https');
         }
 
         assert_equals(actual.redirectStart, 0, 'redirectStart should be 0');
         assert_equals(actual.redirectEnd, 0, 'redirectEnd should be 0');
-        assert_true(actual.secureConnectionStart == undefined ||
-                    actual.secureConnectionStart == 0, 'secureConnectionStart should be 0 or undefined');
         assert_equals(actual.fetchStart, actual.startTime, 'fetchStart is equal to startTime');
         assert_greater_than_equal(actual.domainLookupStart, actual.fetchStart, 'domainLookupStart after fetchStart');
         assert_greater_than_equal(actual.domainLookupEnd, actual.domainLookupStart, 'domainLookupEnd after domainLookupStart');
         assert_greater_than_equal(actual.connectStart, actual.domainLookupEnd, 'connectStart after domainLookupEnd');
         assert_greater_than_equal(actual.connectEnd, actual.connectStart, 'connectEnd after connectStart');
+        assert_true(actual.secureConnectionStart == 0 || actual.secureConnectionStart <= actual.requestStart,
+            "secureConnectionStart should be either 0 or smaller than/equals to requestStart")
         assert_greater_than_equal(actual.requestStart, actual.connectEnd, 'requestStart after connectEnd');
         assert_greater_than_equal(actual.responseStart, actual.requestStart, 'responseStart after requestStart');
         assert_greater_than_equal(actual.responseEnd, actual.responseStart, 'responseEnd after responseStart');
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-createXXX.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-createXXX.tentative.html
index 6a0151a..475a264 100644
--- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-createXXX.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicy-createXXX.tentative.html
@@ -36,7 +36,7 @@
     assert_equals(el.title, INPUTS.URL);
 
     el.title = policy.createURL(INPUTS.HTML);
-    assert_equals(el.title, "");
+    assert_equals(el.title, INPUTS.HTML);
   }, "Attributes without type constraints will work as before.");
 
   test(t => {
@@ -71,14 +71,14 @@
 
   const urlTestCases = [
     [ s => s, INPUTS.SCRIPTURL ],
-    [ s => null, "" ],
+    [ s => null, "null" ],
     [ s => s + "#duck", INPUTS.SCRIPTURL + "#duck" ],
     [ s => { throw new Error() }, new Error() ],
     [ s => s + "#" + aGlobalVarForSideEffectTesting,
       INPUTS.SCRIPTURL + "#global" ],
     [ anotherGlobalFunction.bind(aGlobalObject), INPUTS.SCRIPTURL + "#well," ],
     [ s => anotherGlobalFunction(s),
-      INPUTS.SCRIPTURL + "#a%20global%20var%20named%20foo" ],
+      INPUTS.SCRIPTURL + "#a global var named foo" ],
   ];
 
   function policyBuilder(trustedMethodName, trustedType, defaultArg) {
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html
index a162d84c..37e245ee 100644
--- a/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-createXYZTests.tentative.html
@@ -165,7 +165,7 @@
   }, "script_url = identity function");
 
   test(t => {
-    createScriptURLTest('TestPolicyScriptURL2', { createScriptURL: s => null }, "", t);
+    createScriptURLTest('TestPolicyScriptURL2', { createScriptURL: s => null }, "null", t);
   }, "script_url = null");
 
   var scriptURLstr = '#duck';
@@ -240,7 +240,7 @@
   }, "url = identity function");
 
   test(t => {
-    createURLTest('TestPolicyURL2', { createURL: s => null }, "", t);
+    createURLTest('TestPolicyURL2', { createURL: s => null }, "null", t);
   }, "url = null");
 
   var URLstr = '#x';
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html
index b24ab69..c243757 100644
--- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html
@@ -66,20 +66,14 @@
   URLTestCases.forEach(c => {
     test(t => {
       assert_element_accepts_trusted_type(c[0], c[1], INPUTS.URL, RESULTS.URL);
-
-      // Properties that actually parse the URLs will resort to the base URL
-      // when given a null or empty URL.
-      assert_element_accepts_trusted_type(c[0], c[1], null, "" + window.location);
+      assert_element_accepts_trusted_type(c[0], c[1], null, window.location.toString().replace(/[^\/]*$/, "null"));
     }, c[0] + "." + c[1] + " accepts string and null after default policy was created.");
   });
 
   scriptURLTestCases.forEach(c => {
     test(t => {
       assert_element_accepts_trusted_type(c[0], c[1], INPUTS.SCRIPTURL, RESULTS.SCRIPTURL);
-
-      // Properties that actually parse the URLs will resort to the base URL
-      // when given a null or empty URL.
-      assert_element_accepts_trusted_type(c[0], c[1], null, "" + window.location);
+      assert_element_accepts_trusted_type(c[0], c[1], null, window.location.toString().replace(/[^\/]*$/, "null"));
     }, c[0] + "." + c[1] + " accepts string and null after default policy was created.");
   });
 
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html
index 0eef00b..4a5c2cc 100644
--- a/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html
@@ -71,14 +71,14 @@
   URLTestCases.forEach(c => {
     test(t => {
       assert_element_accepts_trusted_type(c[0], c[1], INPUTS.URL, RESULTS.URL);
-      assert_element_accepts_trusted_type(c[0], c[1], null, "" + window.location);
+      assert_element_accepts_trusted_type(c[0], c[1], null, window.location.toString().replace(/[^\/]*$/, "null"));
     }, c[0] + "." + c[1] + " accepts string and null after default policy was created");
   });
 
   scriptURLTestCases.forEach(c => {
     test(t => {
       assert_element_accepts_trusted_type(c[0], c[1], INPUTS.SCRIPTURL, RESULTS.SCRIPTURL);
-      assert_element_accepts_trusted_type(c[0], c[1], null, "" + window.location);
+      assert_element_accepts_trusted_type(c[0], c[1], null, window.location.toString().replace(/[^\/]*$/, "null"));
     }, c[0] + "." + c[1] + " accepts string and null after default policy was created");
   });
 
diff --git a/third_party/blink/web_tests/external/wpt/workers/semantics/structured-clone/dedicated-expected.txt b/third_party/blink/web_tests/external/wpt/workers/semantics/structured-clone/dedicated-expected.txt
deleted file mode 100644
index 3c8beb85..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/semantics/structured-clone/dedicated-expected.txt
+++ /dev/null
@@ -1,119 +0,0 @@
-This is a testharness.js-based test.
-Found 115 tests; 112 PASS, 3 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS primitive undefined
-PASS primitive null
-PASS primitive true
-PASS primitive false
-PASS primitive string, empty string
-PASS primitive string, lone high surrogate
-PASS primitive string, lone low surrogate
-PASS primitive string, NUL
-PASS primitive string, astral character
-PASS primitive number, 0.2
-PASS primitive number, 0
-PASS primitive number, -0
-PASS primitive number, NaN
-PASS primitive number, Infinity
-PASS primitive number, -Infinity
-PASS primitive number, 9007199254740992
-PASS primitive number, -9007199254740992
-PASS primitive number, 9007199254740994
-PASS primitive number, -9007199254740994
-PASS Array primitives
-PASS Object primitives
-PASS Boolean true
-PASS Boolean false
-PASS Array Boolean objects
-PASS Object Boolean objects
-PASS String empty string
-PASS String lone high surrogate
-PASS String lone low surrogate
-PASS String NUL
-PASS String astral character
-PASS Array String objects
-PASS Object String objects
-PASS Number 0.2
-PASS Number 0
-PASS Number -0
-PASS Number NaN
-PASS Number Infinity
-PASS Number -Infinity
-PASS Number 9007199254740992
-PASS Number -9007199254740992
-PASS Number 9007199254740994
-PASS Number -9007199254740994
-PASS Array Number objects
-PASS Object Number objects
-PASS Date 0
-PASS Date -0
-PASS Date -8.64e15
-PASS Date 8.64e15
-PASS Array Date objects
-PASS Object Date objects
-PASS RegExp flags and lastIndex
-PASS RegExp sticky flag
-PASS RegExp unicode flag
-PASS RegExp empty
-PASS RegExp slash
-FAIL RegExp new line assert_equals: source expected "\\n" but got "\n"
-PASS Array RegExp object, RegExp flags and lastIndex
-PASS Array RegExp object, RegExp sticky flag
-PASS Array RegExp object, RegExp unicode flag
-PASS Array RegExp object, RegExp empty
-PASS Array RegExp object, RegExp slash
-FAIL Array RegExp object, RegExp new line assert_equals: source expected "\\n" but got "\n"
-PASS Object RegExp object, RegExp flags and lastIndex
-PASS Object RegExp object, RegExp sticky flag
-PASS Object RegExp object, RegExp unicode flag
-PASS Object RegExp object, RegExp empty
-PASS Object RegExp object, RegExp slash
-FAIL Object RegExp object, RegExp new line assert_equals: source expected "\\n" but got "\n"
-PASS Blob basic
-PASS Blob unpaired high surrogate (invalid utf-8)
-PASS Blob unpaired low surrogate (invalid utf-8)
-PASS Blob paired surrogates (invalid utf-8)
-PASS Blob empty
-PASS Blob NUL
-PASS Array Blob object, Blob basic
-PASS Array Blob object, Blob unpaired high surrogate (invalid utf-8)
-PASS Array Blob object, Blob unpaired low surrogate (invalid utf-8)
-PASS Array Blob object, Blob paired surrogates (invalid utf-8)
-PASS Array Blob object, Blob empty
-PASS Array Blob object, Blob NUL
-PASS Object Blob object, Blob basic
-PASS Object Blob object, Blob unpaired high surrogate (invalid utf-8)
-PASS Object Blob object, Blob unpaired low surrogate (invalid utf-8)
-PASS Object Blob object, Blob paired surrogates (invalid utf-8)
-PASS Object Blob object, Blob empty
-PASS Object Blob object, Blob NUL
-PASS File basic
-PASS FileList empty
-PASS Array FileList object, FileList empty
-PASS Object FileList object, FileList empty
-PASS ImageData 1x1 transparent black
-PASS ImageData 1x1 non-transparent non-black
-PASS Array ImageData object, ImageData 1x1 transparent black
-PASS Array ImageData object, ImageData 1x1 non-transparent non-black
-PASS Object ImageData object, ImageData 1x1 transparent black
-PASS Object ImageData object, ImageData 1x1 non-transparent non-black
-PASS Array sparse
-PASS Array with non-index property
-PASS Object with index property and length
-PASS Array with circular reference
-PASS Object with circular reference
-PASS Array with identical property values
-PASS Object with identical property values
-PASS Object with property on prototype
-PASS Object with non-enumerable property
-PASS Object with non-writable property
-PASS Object with non-configurable property
-PASS ImageBitmap 1x1 transparent black
-PASS ImageBitmap 1x1 non-transparent non-black
-PASS Array ImageBitmap object, ImageBitmap 1x1 transparent black
-PASS Array ImageBitmap object, ImageBitmap 1x1 transparent non-black
-PASS Object ImageBitmap object, ImageBitmap 1x1 transparent black
-PASS Object ImageBitmap object, ImageBitmap 1x1 transparent non-black
-PASS ArrayBuffer
-PASS MessagePort
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/workers/semantics/structured-clone/shared-expected.txt b/third_party/blink/web_tests/external/wpt/workers/semantics/structured-clone/shared-expected.txt
deleted file mode 100644
index 3c8beb85..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/semantics/structured-clone/shared-expected.txt
+++ /dev/null
@@ -1,119 +0,0 @@
-This is a testharness.js-based test.
-Found 115 tests; 112 PASS, 3 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS primitive undefined
-PASS primitive null
-PASS primitive true
-PASS primitive false
-PASS primitive string, empty string
-PASS primitive string, lone high surrogate
-PASS primitive string, lone low surrogate
-PASS primitive string, NUL
-PASS primitive string, astral character
-PASS primitive number, 0.2
-PASS primitive number, 0
-PASS primitive number, -0
-PASS primitive number, NaN
-PASS primitive number, Infinity
-PASS primitive number, -Infinity
-PASS primitive number, 9007199254740992
-PASS primitive number, -9007199254740992
-PASS primitive number, 9007199254740994
-PASS primitive number, -9007199254740994
-PASS Array primitives
-PASS Object primitives
-PASS Boolean true
-PASS Boolean false
-PASS Array Boolean objects
-PASS Object Boolean objects
-PASS String empty string
-PASS String lone high surrogate
-PASS String lone low surrogate
-PASS String NUL
-PASS String astral character
-PASS Array String objects
-PASS Object String objects
-PASS Number 0.2
-PASS Number 0
-PASS Number -0
-PASS Number NaN
-PASS Number Infinity
-PASS Number -Infinity
-PASS Number 9007199254740992
-PASS Number -9007199254740992
-PASS Number 9007199254740994
-PASS Number -9007199254740994
-PASS Array Number objects
-PASS Object Number objects
-PASS Date 0
-PASS Date -0
-PASS Date -8.64e15
-PASS Date 8.64e15
-PASS Array Date objects
-PASS Object Date objects
-PASS RegExp flags and lastIndex
-PASS RegExp sticky flag
-PASS RegExp unicode flag
-PASS RegExp empty
-PASS RegExp slash
-FAIL RegExp new line assert_equals: source expected "\\n" but got "\n"
-PASS Array RegExp object, RegExp flags and lastIndex
-PASS Array RegExp object, RegExp sticky flag
-PASS Array RegExp object, RegExp unicode flag
-PASS Array RegExp object, RegExp empty
-PASS Array RegExp object, RegExp slash
-FAIL Array RegExp object, RegExp new line assert_equals: source expected "\\n" but got "\n"
-PASS Object RegExp object, RegExp flags and lastIndex
-PASS Object RegExp object, RegExp sticky flag
-PASS Object RegExp object, RegExp unicode flag
-PASS Object RegExp object, RegExp empty
-PASS Object RegExp object, RegExp slash
-FAIL Object RegExp object, RegExp new line assert_equals: source expected "\\n" but got "\n"
-PASS Blob basic
-PASS Blob unpaired high surrogate (invalid utf-8)
-PASS Blob unpaired low surrogate (invalid utf-8)
-PASS Blob paired surrogates (invalid utf-8)
-PASS Blob empty
-PASS Blob NUL
-PASS Array Blob object, Blob basic
-PASS Array Blob object, Blob unpaired high surrogate (invalid utf-8)
-PASS Array Blob object, Blob unpaired low surrogate (invalid utf-8)
-PASS Array Blob object, Blob paired surrogates (invalid utf-8)
-PASS Array Blob object, Blob empty
-PASS Array Blob object, Blob NUL
-PASS Object Blob object, Blob basic
-PASS Object Blob object, Blob unpaired high surrogate (invalid utf-8)
-PASS Object Blob object, Blob unpaired low surrogate (invalid utf-8)
-PASS Object Blob object, Blob paired surrogates (invalid utf-8)
-PASS Object Blob object, Blob empty
-PASS Object Blob object, Blob NUL
-PASS File basic
-PASS FileList empty
-PASS Array FileList object, FileList empty
-PASS Object FileList object, FileList empty
-PASS ImageData 1x1 transparent black
-PASS ImageData 1x1 non-transparent non-black
-PASS Array ImageData object, ImageData 1x1 transparent black
-PASS Array ImageData object, ImageData 1x1 non-transparent non-black
-PASS Object ImageData object, ImageData 1x1 transparent black
-PASS Object ImageData object, ImageData 1x1 non-transparent non-black
-PASS Array sparse
-PASS Array with non-index property
-PASS Object with index property and length
-PASS Array with circular reference
-PASS Object with circular reference
-PASS Array with identical property values
-PASS Object with identical property values
-PASS Object with property on prototype
-PASS Object with non-enumerable property
-PASS Object with non-writable property
-PASS Object with non-configurable property
-PASS ImageBitmap 1x1 transparent black
-PASS ImageBitmap 1x1 non-transparent non-black
-PASS Array ImageBitmap object, ImageBitmap 1x1 transparent black
-PASS Array ImageBitmap object, ImageBitmap 1x1 transparent non-black
-PASS Object ImageBitmap object, ImageBitmap 1x1 transparent black
-PASS Object ImageBitmap object, ImageBitmap 1x1 transparent non-black
-PASS ArrayBuffer
-PASS MessagePort
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid.html
index 1ba7d88b..415ea6e 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid.html
@@ -303,8 +303,8 @@
      fillGridElement.style.gridGap = "1000000px";
      fitGridElement.style.gridGap = "1000000px";
 
-     testElement("wideAutoFillGridFewRepetitions", "grid-template-columns", 130);
-     testElement("wideAutoFitGridFewRepetitions", "grid-template-columns", 82);
+     testElement("wideAutoFillGridFewRepetitions", "grid-template-columns", 30);
+     testElement("wideAutoFitGridFewRepetitions", "grid-template-columns", 34);
 
      fillGridElement.style.gridGap = "0px";
      fitGridElement.style.gridGap = "0px";
@@ -328,8 +328,8 @@
      autoFillGridElement.style.gridGap = "1000000px";
      autoFitGridElement.style.gridGap = "1000000px";
 
-     testElement("tallAutoFillGridFewRepetitions", "grid-template-rows", 130);
-     testElement("tallAutoFitGridFewRepetitions", "grid-template-rows", 82);
+     testElement("tallAutoFillGridFewRepetitions", "grid-template-rows", 30);
+     testElement("tallAutoFitGridFewRepetitions", "grid-template-rows", 34);
 
      autoFillGridElement.style.gridGap = "0px";
      autoFitGridElement.style.gridGap = "0px";
diff --git a/third_party/libjingle_xmpp/BUILD.gn b/third_party/libjingle_xmpp/BUILD.gn
index 5755001..1be7995c 100644
--- a/third_party/libjingle_xmpp/BUILD.gn
+++ b/third_party/libjingle_xmpp/BUILD.gn
@@ -54,18 +54,7 @@
   public_deps = [
     "//third_party/expat",
   ]
-  all_dependent_configs = [
-    ":libjingle_xmpp_common_config",
-  ]
-}
-
-config("rtc_xmpp_warnings_config") {
-  # GN orders flags on a target before flags from configs. The default config
-  # adds these flags so to cancel them out they need to come from a config and
-  # cannot be on the target directly.
-  if (is_android) {
-    cflags = [ "-Wno-error" ]
-  }
+  all_dependent_configs = [ ":libjingle_xmpp_common_config" ]
 }
 
 rtc_static_library("rtc_xmpp") {
@@ -110,7 +99,6 @@
     ":rtc_task_runner",
     "//third_party/expat",
   ]
-  configs += [ ":rtc_xmpp_warnings_config" ]
   all_dependent_configs = [ ":libjingle_xmpp_common_config" ]
 
   if (is_nacl) {
@@ -139,10 +127,6 @@
     ":rtc_task_runner",
     "//base/test:run_all_unittests",
     "//base/test:test_support",
-
-    # TODO(kjellander): Refactor/remove this dependency. It is needed by
-    # third_party/webrtc_overrides/rtc_base/win32socketinit.cc.
-    "//net",
     "//testing/gtest",
   ]
 
diff --git a/third_party/libjingle_xmpp/DEPS b/third_party/libjingle_xmpp/DEPS
index 4d25c08..9524d2f 100644
--- a/third_party/libjingle_xmpp/DEPS
+++ b/third_party/libjingle_xmpp/DEPS
@@ -1,5 +1,5 @@
 specific_include_rules = {
-  "run_all_unittests\.cc": [
+  ".*_unittest\.cc": [
     "+testing",
   ]
 }
diff --git a/third_party/libjingle_xmpp/task_runner/task.h b/third_party/libjingle_xmpp/task_runner/task.h
index 4111470c..90c91609 100644
--- a/third_party/libjingle_xmpp/task_runner/task.h
+++ b/third_party/libjingle_xmpp/task_runner/task.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_BASE_TASK_H__
-#define WEBRTC_BASE_TASK_H__
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_TASK_RUNNER_TASK_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_TASK_RUNNER_TASK_H_
 
 #include <stdint.h>
 
@@ -172,4 +172,4 @@
 
 }  // namespace rtc
 
-#endif  // WEBRTC_BASE_TASK_H__
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_TASK_RUNNER_TASK_H_
diff --git a/third_party/libjingle_xmpp/task_runner/task_unittest.cc b/third_party/libjingle_xmpp/task_runner/task_unittest.cc
index b314c13..234d524 100644
--- a/third_party/libjingle_xmpp/task_runner/task_unittest.cc
+++ b/third_party/libjingle_xmpp/task_runner/task_unittest.cc
@@ -20,11 +20,11 @@
 #include "third_party/webrtc/rtc_base/win32.h"
 #endif  // WEBRTC_WIN
 
+#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/libjingle_xmpp/task_runner/task.h"
 #include "third_party/libjingle_xmpp/task_runner/taskrunner.h"
 #include "third_party/webrtc/rtc_base/arraysize.h"
 #include "third_party/webrtc/rtc_base/constructormagic.h"
-#include "third_party/webrtc/rtc_base/gunit.h"
 #include "third_party/webrtc/rtc_base/thread.h"
 #include "third_party/webrtc/rtc_base/timeutils.h"
 #include "third_party/webrtc_overrides/rtc_base/logging.h"
diff --git a/third_party/libjingle_xmpp/task_runner/taskparent.h b/third_party/libjingle_xmpp/task_runner/taskparent.h
index 89dc2ce..b4daa48 100644
--- a/third_party/libjingle_xmpp/task_runner/taskparent.h
+++ b/third_party/libjingle_xmpp/task_runner/taskparent.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_BASE_TASKPARENT_H__
-#define WEBRTC_BASE_TASKPARENT_H__
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_TASK_RUNNER_TASKPARENT_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_TASK_RUNNER_TASKPARENT_H_
 
 #include <memory>
 #include <set>
@@ -60,4 +60,4 @@
 
 } // namespace rtc
 
-#endif  // WEBRTC_BASE_TASKPARENT_H__
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_TASK_RUNNER_TASKPARENT_H_
diff --git a/third_party/libjingle_xmpp/task_runner/taskrunner.h b/third_party/libjingle_xmpp/task_runner/taskrunner.h
index 0c54899..443ddbb 100644
--- a/third_party/libjingle_xmpp/task_runner/taskrunner.h
+++ b/third_party/libjingle_xmpp/task_runner/taskrunner.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_BASE_TASKRUNNER_H__
-#define WEBRTC_BASE_TASKRUNNER_H__
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_TASK_RUNNER_TASKRUNNER_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_TASK_RUNNER_TASKRUNNER_H_
 
 #include <stdint.h>
 
@@ -99,4 +99,4 @@
 
 } // namespace rtc
 
-#endif  // TASK_BASE_TASKRUNNER_H__
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_TASK_RUNNER_TASKRUNNER_H_
diff --git a/third_party/libjingle_xmpp/xmllite/qname.h b/third_party/libjingle_xmpp/xmllite/qname.h
index 1e772d3..8da3a00 100644
--- a/third_party/libjingle_xmpp/xmllite/qname.h
+++ b/third_party/libjingle_xmpp/xmllite/qname.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMLLITE_QNAME_H_
-#define WEBRTC_LIBJINGLE_XMLLITE_QNAME_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_QNAME_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_QNAME_H_
 
 #include <string>
 
@@ -80,4 +80,4 @@
 
 }  // namespace buzz
 
-#endif  // WEBRTC_LIBJINGLE_XMLLITE_QNAME_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_QNAME_H_
diff --git a/third_party/libjingle_xmpp/xmllite/qname_unittest.cc b/third_party/libjingle_xmpp/xmllite/qname_unittest.cc
index 4673079..bafea9d3 100644
--- a/third_party/libjingle_xmpp/xmllite/qname_unittest.cc
+++ b/third_party/libjingle_xmpp/xmllite/qname_unittest.cc
@@ -9,8 +9,9 @@
  */
 
 #include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/libjingle_xmpp/xmllite/qname.h"
-#include "third_party/webrtc/rtc_base/gunit.h"
 
 using buzz::StaticQName;
 using buzz::QName;
diff --git a/third_party/libjingle_xmpp/xmllite/xmlbuilder.h b/third_party/libjingle_xmpp/xmllite/xmlbuilder.h
index 4acf3fe..2ed673a 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlbuilder.h
+++ b/third_party/libjingle_xmpp/xmllite/xmlbuilder.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef _xmlbuilder_h_
-#define _xmlbuilder_h_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLBUILDER_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLBUILDER_H_
 
 #include <memory>
 #include <string>
@@ -58,4 +58,4 @@
 
 }
 
-#endif
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLBUILDER_H_
diff --git a/third_party/libjingle_xmpp/xmllite/xmlbuilder_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlbuilder_unittest.cc
index 65b8083..f203fded 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlbuilder_unittest.cc
+++ b/third_party/libjingle_xmpp/xmllite/xmlbuilder_unittest.cc
@@ -11,10 +11,11 @@
 #include <iostream>
 #include <sstream>
 #include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlbuilder.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlparser.h"
-#include "third_party/webrtc/rtc_base/gunit.h"
 
 using buzz::XmlBuilder;
 using buzz::XmlElement;
diff --git a/third_party/libjingle_xmpp/xmllite/xmlconstants.h b/third_party/libjingle_xmpp/xmllite/xmlconstants.h
index 1499a084..a777cb0d 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlconstants.h
+++ b/third_party/libjingle_xmpp/xmllite/xmlconstants.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLCONSTANTS_H_
-#define WEBRTC_LIBJINGLE_XMLLITE_XMLCONSTANTS_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLCONSTANTS_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLCONSTANTS_H_
 
 #include "third_party/libjingle_xmpp/xmllite/qname.h"
 
@@ -27,4 +27,4 @@
 
 }  // namespace buzz
 
-#endif  // WEBRTC_LIBJINGLE_XMLLITE_XMLCONSTANTS_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLCONSTANTS_H_
diff --git a/third_party/libjingle_xmpp/xmllite/xmlelement.h b/third_party/libjingle_xmpp/xmllite/xmlelement.h
index bec6f99..2992dc4f 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlelement.h
+++ b/third_party/libjingle_xmpp/xmllite/xmlelement.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLELEMENT_H_
-#define WEBRTC_LIBJINGLE_XMLLITE_XMLELEMENT_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLELEMENT_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLELEMENT_H_
 
 #include <iosfwd>
 #include <string>
@@ -230,4 +230,4 @@
 
 }  // namespace buzz
 
-#endif  // WEBRTC_LIBJINGLE_XMLLITE_XMLELEMENT_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLELEMENT_H_
diff --git a/third_party/libjingle_xmpp/xmllite/xmlelement_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlelement_unittest.cc
index 38fc6d2..70fb9355 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlelement_unittest.cc
+++ b/third_party/libjingle_xmpp/xmllite/xmlelement_unittest.cc
@@ -11,8 +11,9 @@
 #include <iostream>
 #include <sstream>
 #include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
-#include "third_party/webrtc/rtc_base/gunit.h"
 #include "third_party/webrtc/rtc_base/thread.h"
 
 using buzz::QName;
diff --git a/third_party/libjingle_xmpp/xmllite/xmlnsstack.h b/third_party/libjingle_xmpp/xmllite/xmlnsstack.h
index c6200a9..646726e 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlnsstack.h
+++ b/third_party/libjingle_xmpp/xmllite/xmlnsstack.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLNSSTACK_H_
-#define WEBRTC_LIBJINGLE_XMLLITE_XMLNSSTACK_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLNSSTACK_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLNSSTACK_H_
 
 #include <memory>
 #include <string>
@@ -42,4 +42,4 @@
 };
 }
 
-#endif  // WEBRTC_LIBJINGLE_XMLLITE_XMLNSSTACK_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLNSSTACK_H_
diff --git a/third_party/libjingle_xmpp/xmllite/xmlnsstack_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlnsstack_unittest.cc
index 3480e9eb..22b01cf 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlnsstack_unittest.cc
+++ b/third_party/libjingle_xmpp/xmllite/xmlnsstack_unittest.cc
@@ -14,8 +14,8 @@
 #include <sstream>
 #include <string>
 
+#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
-#include "third_party/webrtc/rtc_base/gunit.h"
 
 using buzz::NS_XML;
 using buzz::NS_XMLNS;
diff --git a/third_party/libjingle_xmpp/xmllite/xmlparser.h b/third_party/libjingle_xmpp/xmllite/xmlparser.h
index 677dec6..61c016e 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlparser.h
+++ b/third_party/libjingle_xmpp/xmllite/xmlparser.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLPARSER_H_
-#define WEBRTC_LIBJINGLE_XMLLITE_XMLPARSER_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLPARSER_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLPARSER_H_
 
 #include <string>
 
@@ -100,4 +100,4 @@
 
 }  // namespace buzz
 
-#endif  // WEBRTC_LIBJINGLE_XMLLITE_XMLPARSER_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLPARSER_H_
diff --git a/third_party/libjingle_xmpp/xmllite/xmlparser_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlparser_unittest.cc
index 30bdb85..33522a4 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlparser_unittest.cc
+++ b/third_party/libjingle_xmpp/xmllite/xmlparser_unittest.cc
@@ -11,9 +11,10 @@
 #include <iostream>
 #include <sstream>
 #include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/libjingle_xmpp/xmllite/qname.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlparser.h"
-#include "third_party/webrtc/rtc_base/gunit.h"
 
 using buzz::QName;
 using buzz::XmlParser;
diff --git a/third_party/libjingle_xmpp/xmllite/xmlprinter.h b/third_party/libjingle_xmpp/xmllite/xmlprinter.h
index 40cf195..45a5be2 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlprinter.h
+++ b/third_party/libjingle_xmpp/xmllite/xmlprinter.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMLLITE_XMLPRINTER_H_
-#define WEBRTC_LIBJINGLE_XMLLITE_XMLPRINTER_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLPRINTER_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLPRINTER_H_
 
 #include <iosfwd>
 #include <string>
@@ -29,4 +29,4 @@
 
 }  // namespace buzz
 
-#endif  // WEBRTC_LIBJINGLE_XMLLITE_XMLPRINTER_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMLLITE_XMLPRINTER_H_
diff --git a/third_party/libjingle_xmpp/xmllite/xmlprinter_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlprinter_unittest.cc
index 4be90be..c35e2d5 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlprinter_unittest.cc
+++ b/third_party/libjingle_xmpp/xmllite/xmlprinter_unittest.cc
@@ -13,10 +13,10 @@
 #include <sstream>
 #include <string>
 
+#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/libjingle_xmpp/xmllite/qname.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlnsstack.h"
-#include "third_party/webrtc/rtc_base/gunit.h"
 
 using buzz::QName;
 using buzz::XmlElement;
diff --git a/third_party/libjingle_xmpp/xmpp/asyncsocket.h b/third_party/libjingle_xmpp/xmpp/asyncsocket.h
index 6be51d7..e56a8d4 100644
--- a/third_party/libjingle_xmpp/xmpp/asyncsocket.h
+++ b/third_party/libjingle_xmpp/xmpp/asyncsocket.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_ASYNCSOCKET_H_
-#define WEBRTC_LIBJINGLE_XMPP_ASYNCSOCKET_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_ASYNCSOCKET_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_ASYNCSOCKET_H_
 
 #include <string>
 
@@ -63,4 +63,4 @@
 
 }
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_ASYNCSOCKET_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_ASYNCSOCKET_H_
diff --git a/third_party/libjingle_xmpp/xmpp/constants.h b/third_party/libjingle_xmpp/xmpp/constants.h
index 16bed97..f5bfcd0 100644
--- a/third_party/libjingle_xmpp/xmpp/constants.h
+++ b/third_party/libjingle_xmpp/xmpp/constants.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_CONSTANTS_H_
-#define WEBRTC_LIBJINGLE_XMPP_CONSTANTS_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_CONSTANTS_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_CONSTANTS_H_
 
 #include <string>
 #include "third_party/libjingle_xmpp/xmllite/qname.h"
@@ -546,4 +546,4 @@
 
 }  // namespace buzz
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_CONSTANTS_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_CONSTANTS_H_
diff --git a/third_party/libjingle_xmpp/xmpp/fakexmppclient.h b/third_party/libjingle_xmpp/xmpp/fakexmppclient.h
index 988fbe3..667a980 100644
--- a/third_party/libjingle_xmpp/xmpp/fakexmppclient.h
+++ b/third_party/libjingle_xmpp/xmpp/fakexmppclient.h
@@ -10,8 +10,8 @@
 
 // A fake XmppClient for use in unit tests.
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_FAKEXMPPCLIENT_H_
-#define WEBRTC_LIBJINGLE_XMPP_FAKEXMPPCLIENT_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_FAKEXMPPCLIENT_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_FAKEXMPPCLIENT_H_
 
 #include <algorithm>
 #include <string>
@@ -104,4 +104,4 @@
 
 }  // namespace buzz
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_FAKEXMPPCLIENT_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_FAKEXMPPCLIENT_H_
diff --git a/third_party/libjingle_xmpp/xmpp/jid.h b/third_party/libjingle_xmpp/xmpp/jid.h
index 5443b05..35d70ab 100644
--- a/third_party/libjingle_xmpp/xmpp/jid.h
+++ b/third_party/libjingle_xmpp/xmpp/jid.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_JID_H_
-#define WEBRTC_LIBJINGLE_XMPP_JID_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_JID_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_JID_H_
 
 #include <string>
 #include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
@@ -77,4 +77,4 @@
 
 }
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_JID_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_JID_H_
diff --git a/third_party/libjingle_xmpp/xmpp/jid_unittest.cc b/third_party/libjingle_xmpp/xmpp/jid_unittest.cc
index 982abe1..46b1df9 100644
--- a/third_party/libjingle_xmpp/xmpp/jid_unittest.cc
+++ b/third_party/libjingle_xmpp/xmpp/jid_unittest.cc
@@ -9,7 +9,7 @@
  */
 
 #include "third_party/libjingle_xmpp/xmpp/jid.h"
-#include "third_party/webrtc/rtc_base/gunit.h"
+#include "testing/gtest/include/gtest/gtest.h"
 
 using buzz::Jid;
 
diff --git a/third_party/libjingle_xmpp/xmpp/jingleinfotask.h b/third_party/libjingle_xmpp/xmpp/jingleinfotask.h
index b1637f84..44058d6 100644
--- a/third_party/libjingle_xmpp/xmpp/jingleinfotask.h
+++ b/third_party/libjingle_xmpp/xmpp/jingleinfotask.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef THIRD_PARTY_XMPP_JINGLEINFOTASK_H_
-#define THIRD_PARTY_XMPP_JINGLEINFOTASK_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_JINGLEINFOTASK_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_JINGLEINFOTASK_H_
 
 #include <vector>
 
@@ -41,4 +41,4 @@
 };
 }
 
-#endif  // THIRD_PARTY_XMPP_JINGLEINFOTASK_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_JINGLEINFOTASK_H_
diff --git a/third_party/libjingle_xmpp/xmpp/plainsaslhandler.h b/third_party/libjingle_xmpp/xmpp/plainsaslhandler.h
index a25d54f..5435540 100644
--- a/third_party/libjingle_xmpp/xmpp/plainsaslhandler.h
+++ b/third_party/libjingle_xmpp/xmpp/plainsaslhandler.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_PLAINSASLHANDLER_H_
-#define WEBRTC_LIBJINGLE_XMPP_PLAINSASLHANDLER_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_PLAINSASLHANDLER_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_PLAINSASLHANDLER_H_
 
 #include <algorithm>
 #include "third_party/libjingle_xmpp/xmpp/saslhandler.h"
@@ -60,4 +60,4 @@
 
 }
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_PLAINSASLHANDLER_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_PLAINSASLHANDLER_H_
diff --git a/third_party/libjingle_xmpp/xmpp/prexmppauth.h b/third_party/libjingle_xmpp/xmpp/prexmppauth.h
index 60de88c..2ba0f4b 100644
--- a/third_party/libjingle_xmpp/xmpp/prexmppauth.h
+++ b/third_party/libjingle_xmpp/xmpp/prexmppauth.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_PREXMPPAUTH_H_
-#define WEBRTC_LIBJINGLE_XMPP_PREXMPPAUTH_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_PREXMPPAUTH_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_PREXMPPAUTH_H_
 
 #include "third_party/libjingle_xmpp/xmpp/saslhandler.h"
 #include "third_party/webrtc/rtc_base/third_party/sigslot/sigslot.h"
@@ -67,4 +67,4 @@
 
 }
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_PREXMPPAUTH_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_PREXMPPAUTH_H_
diff --git a/third_party/libjingle_xmpp/xmpp/saslcookiemechanism.h b/third_party/libjingle_xmpp/xmpp/saslcookiemechanism.h
index 83442b95..8a4281f 100644
--- a/third_party/libjingle_xmpp/xmpp/saslcookiemechanism.h
+++ b/third_party/libjingle_xmpp/xmpp/saslcookiemechanism.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_SASLCOOKIEMECHANISM_H_
-#define WEBRTC_LIBJINGLE_XMPP_SASLCOOKIEMECHANISM_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_SASLCOOKIEMECHANISM_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_SASLCOOKIEMECHANISM_H_
 
 #include "third_party/libjingle_xmpp/xmllite/qname.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
@@ -66,4 +66,4 @@
 
 }
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_SASLCOOKIEMECHANISM_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_SASLCOOKIEMECHANISM_H_
diff --git a/third_party/libjingle_xmpp/xmpp/saslhandler.h b/third_party/libjingle_xmpp/xmpp/saslhandler.h
index 0dccf41..7c36040 100644
--- a/third_party/libjingle_xmpp/xmpp/saslhandler.h
+++ b/third_party/libjingle_xmpp/xmpp/saslhandler.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_SASLHANDLER_H_
-#define WEBRTC_LIBJINGLE_XMPP_SASLHANDLER_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_SASLHANDLER_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_SASLHANDLER_H_
 
 #include <string>
 #include <vector>
@@ -39,4 +39,4 @@
 
 }
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_SASLHANDLER_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_SASLHANDLER_H_
diff --git a/third_party/libjingle_xmpp/xmpp/saslmechanism.h b/third_party/libjingle_xmpp/xmpp/saslmechanism.h
index 14b93df..3efc2ea 100644
--- a/third_party/libjingle_xmpp/xmpp/saslmechanism.h
+++ b/third_party/libjingle_xmpp/xmpp/saslmechanism.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_SASLMECHANISM_H_
-#define WEBRTC_LIBJINGLE_XMPP_SASLMECHANISM_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_SASLMECHANISM_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_SASLMECHANISM_H_
 
 #include <string>
 
@@ -54,4 +54,4 @@
 
 }
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_SASLMECHANISM_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_SASLMECHANISM_H_
diff --git a/third_party/libjingle_xmpp/xmpp/saslplainmechanism.h b/third_party/libjingle_xmpp/xmpp/saslplainmechanism.h
index d7319b483..427df5c 100644
--- a/third_party/libjingle_xmpp/xmpp/saslplainmechanism.h
+++ b/third_party/libjingle_xmpp/xmpp/saslplainmechanism.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_SASLPLAINMECHANISM_H_
-#define WEBRTC_LIBJINGLE_XMPP_SASLPLAINMECHANISM_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_SASLPLAINMECHANISM_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_SASLPLAINMECHANISM_H_
 
 #include "third_party/libjingle_xmpp/xmpp/saslmechanism.h"
 
@@ -44,4 +44,4 @@
 
 }
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_SASLPLAINMECHANISM_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_SASLPLAINMECHANISM_H_
diff --git a/third_party/libjingle_xmpp/xmpp/util_unittest.cc b/third_party/libjingle_xmpp/xmpp/util_unittest.cc
index e2af616..bd49c03 100644
--- a/third_party/libjingle_xmpp/xmpp/util_unittest.cc
+++ b/third_party/libjingle_xmpp/xmpp/util_unittest.cc
@@ -11,10 +11,11 @@
 #include <iostream>
 #include <sstream>
 #include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 #include "third_party/libjingle_xmpp/xmpp/util_unittest.h"
 #include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
-#include "third_party/webrtc/rtc_base/gunit.h"
 
 namespace buzz {
 
diff --git a/third_party/libjingle_xmpp/xmpp/util_unittest.h b/third_party/libjingle_xmpp/xmpp/util_unittest.h
index c0f796aa..0a59b81 100644
--- a/third_party/libjingle_xmpp/xmpp/util_unittest.h
+++ b/third_party/libjingle_xmpp/xmpp/util_unittest.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_UTIL_UNITTEST_H_
-#define WEBRTC_LIBJINGLE_XMPP_UTIL_UNITTEST_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_UTIL_UNITTEST_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_UTIL_UNITTEST_H_
 
 #include <sstream>
 #include <string>
@@ -55,4 +55,4 @@
   return os;
 }
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_UTIL_UNITTEST_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_UTIL_UNITTEST_H_
diff --git a/third_party/libjingle_xmpp/xmpp/xmppclient.h b/third_party/libjingle_xmpp/xmpp/xmppclient.h
index ae606ce2..25b0602 100644
--- a/third_party/libjingle_xmpp/xmpp/xmppclient.h
+++ b/third_party/libjingle_xmpp/xmpp/xmppclient.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_
-#define WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPCLIENT_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPCLIENT_H_
 
 #include <memory>
 #include <string>
@@ -146,4 +146,4 @@
 
 }
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPCLIENT_H_
diff --git a/third_party/libjingle_xmpp/xmpp/xmppclientsettings.h b/third_party/libjingle_xmpp/xmpp/xmppclientsettings.h
index 56a57c9..1fb8bbb 100644
--- a/third_party/libjingle_xmpp/xmpp/xmppclientsettings.h
+++ b/third_party/libjingle_xmpp/xmpp/xmppclientsettings.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPCLIENTSETTINGS_H_
-#define WEBRTC_LIBJINGLE_XMPP_XMPPCLIENTSETTINGS_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPCLIENTSETTINGS_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPCLIENTSETTINGS_H_
 
 #include "third_party/webrtc/p2p/base/port.h"
 #include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
@@ -102,4 +102,4 @@
 
 }
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPCLIENT_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPCLIENT_H_
diff --git a/third_party/libjingle_xmpp/xmpp/xmppengine.h b/third_party/libjingle_xmpp/xmpp/xmppengine.h
index fbbcf08..1e6f62f 100644
--- a/third_party/libjingle_xmpp/xmpp/xmppengine.h
+++ b/third_party/libjingle_xmpp/xmpp/xmppengine.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPENGINE_H_
-#define WEBRTC_LIBJINGLE_XMPP_XMPPENGINE_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPENGINE_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPENGINE_H_
 
 // also part of the API
 #include "third_party/libjingle_xmpp/xmllite/qname.h"
@@ -329,4 +329,4 @@
   } while (false)                     \
 
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPENGINE_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPENGINE_H_
diff --git a/third_party/libjingle_xmpp/xmpp/xmppengine_unittest.cc b/third_party/libjingle_xmpp/xmpp/xmppengine_unittest.cc
index ba18d4f..ca35d069 100644
--- a/third_party/libjingle_xmpp/xmpp/xmppengine_unittest.cc
+++ b/third_party/libjingle_xmpp/xmpp/xmppengine_unittest.cc
@@ -13,13 +13,13 @@
 #include <sstream>
 #include <string>
 
+#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 #include "third_party/libjingle_xmpp/xmpp/constants.h"
 #include "third_party/libjingle_xmpp/xmpp/plainsaslhandler.h"
 #include "third_party/libjingle_xmpp/xmpp/saslplainmechanism.h"
 #include "third_party/libjingle_xmpp/xmpp/util_unittest.h"
 #include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
-#include "third_party/webrtc/rtc_base/gunit.h"
 
 using buzz::Jid;
 using buzz::QName;
diff --git a/third_party/libjingle_xmpp/xmpp/xmppengineimpl.h b/third_party/libjingle_xmpp/xmpp/xmppengineimpl.h
index 2f8f2c6..1e88e666 100644
--- a/third_party/libjingle_xmpp/xmpp/xmppengineimpl.h
+++ b/third_party/libjingle_xmpp/xmpp/xmppengineimpl.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPENGINEIMPL_H_
-#define WEBRTC_LIBJINGLE_XMPP_XMPPENGINEIMPL_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPENGINEIMPL_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPENGINEIMPL_H_
 
 #include <memory>
 #include <sstream>
@@ -264,4 +264,4 @@
 
 }  // namespace buzz
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPENGINEIMPL_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPENGINEIMPL_H_
diff --git a/third_party/libjingle_xmpp/xmpp/xmpplogintask.h b/third_party/libjingle_xmpp/xmpp/xmpplogintask.h
index 0d19383..679adf0 100644
--- a/third_party/libjingle_xmpp/xmpp/xmpplogintask.h
+++ b/third_party/libjingle_xmpp/xmpp/xmpplogintask.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_LOGINTASK_H_
-#define WEBRTC_LIBJINGLE_XMPP_LOGINTASK_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_LOGINTASK_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_LOGINTASK_H_
 
 #include <memory>
 #include <string>
@@ -84,4 +84,4 @@
 
 }
 
-#endif  //  WEBRTC_LIBJINGLE_XMPP_LOGINTASK_H_
+#endif  //  THIRD_PARTY_LIBJINGLE_XMPP_XMPP_LOGINTASK_H_
diff --git a/third_party/libjingle_xmpp/xmpp/xmpplogintask_unittest.cc b/third_party/libjingle_xmpp/xmpp/xmpplogintask_unittest.cc
index 815fe47e9..a855a83d 100644
--- a/third_party/libjingle_xmpp/xmpp/xmpplogintask_unittest.cc
+++ b/third_party/libjingle_xmpp/xmpp/xmpplogintask_unittest.cc
@@ -13,13 +13,13 @@
 #include <sstream>
 #include <string>
 
+#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 #include "third_party/libjingle_xmpp/xmpp/constants.h"
 #include "third_party/libjingle_xmpp/xmpp/plainsaslhandler.h"
 #include "third_party/libjingle_xmpp/xmpp/saslplainmechanism.h"
 #include "third_party/libjingle_xmpp/xmpp/util_unittest.h"
 #include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
-#include "third_party/webrtc/rtc_base/gunit.h"
 
 // Macro to be used for switch-case fallthrough (required for enabling
 // -Wimplicit-fallthrough warning on Clang).
diff --git a/third_party/libjingle_xmpp/xmpp/xmppstanzaparser.h b/third_party/libjingle_xmpp/xmpp/xmppstanzaparser.h
index 0c67bf1..61df7e2 100644
--- a/third_party/libjingle_xmpp/xmpp/xmppstanzaparser.h
+++ b/third_party/libjingle_xmpp/xmpp/xmppstanzaparser.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPSTANZAPARSER_H_
-#define WEBRTC_LIBJINGLE_XMPP_XMPPSTANZAPARSER_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPSTANZAPARSER_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPSTANZAPARSER_H_
 
 #include "third_party/libjingle_xmpp/xmllite/xmlbuilder.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlparser.h"
@@ -77,4 +77,4 @@
 
 }
 
-#endif  // WEBRTC_LIBJINGLE_XMPP_XMPPSTANZAPARSER_H_
+#endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPSTANZAPARSER_H_
diff --git a/third_party/libjingle_xmpp/xmpp/xmppstanzaparser_unittest.cc b/third_party/libjingle_xmpp/xmpp/xmppstanzaparser_unittest.cc
index 298d065..85d1fef 100644
--- a/third_party/libjingle_xmpp/xmpp/xmppstanzaparser_unittest.cc
+++ b/third_party/libjingle_xmpp/xmpp/xmppstanzaparser_unittest.cc
@@ -11,9 +11,10 @@
 #include <iostream>
 #include <sstream>
 #include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 #include "third_party/libjingle_xmpp/xmpp/xmppstanzaparser.h"
-#include "third_party/webrtc/rtc_base/gunit.h"
 
 using buzz::QName;
 using buzz::XmlElement;
diff --git a/third_party/libjingle_xmpp/xmpp/xmpptask.h b/third_party/libjingle_xmpp/xmpp/xmpptask.h
index 7537880..a590ddbe 100644
--- a/third_party/libjingle_xmpp/xmpp/xmpptask.h
+++ b/third_party/libjingle_xmpp/xmpp/xmpptask.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_LIBJINGLE_XMPP_XMPPTASK_H_
-#define WEBRTC_LIBJINGLE_XMPP_XMPPTASK_H_
+#ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPTASK_H_
+#define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPTASK_H_
 
 #include <deque>
 #include <memory>
@@ -172,4 +172,4 @@
 
 }  // namespace buzz
 
-#endif // WEBRTC_LIBJINGLE_XMPP_XMPPTASK_H_
+#endif // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPTASK_H_
diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py
index 7051d91..bf947922 100644
--- a/tools/binary_size/libsupersize/archive.py
+++ b/tools/binary_size/libsupersize/archive.py
@@ -85,6 +85,8 @@
           '../../chrome/android/webapk/libs/runtime_library_version.gni'),
       'lib/armeabi-v7a/libarcore_sdk_c_minimal.so': (
           '../../third_party/arcore-android-sdk'),
+      'lib/armeabi-v7a/libarcore_sdk_c.so': (
+          '../../third_party/arcore-android-sdk'),
     }
 
     self.apk_expected_other_files = set([
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 7585c8a9..eb01620 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -17143,6 +17143,14 @@
   </description>
 </action>
 
+<action name="Signin_Impression_FromGoogleServicesSettings">
+  <owner>bsazonov@chromium.org</owner>
+  <owner>jlebel@chromium.org</owner>
+  <description>
+    Recorded when the sign-in promo in the Google services settings is shown.
+  </description>
+</action>
+
 <action name="Signin_Impression_FromManageCardsBubble">
   <owner>manasverma@google.com</owner>
   <owner>jsaul@chromium.org</owner>
@@ -17545,8 +17553,17 @@
   <obsolete>Deprecated as the warning dialog is no longer used.</obsolete>
   <owner>zmin@chromium.org</owner>
   <description>
-    Record when a user signs in again from the force sign in auth error warning
-    modal dialog.
+    Recorded when a user signs in again from the force sign in auth error
+    warning modal dialog.
+  </description>
+</action>
+
+<action name="Signin_Signin_FromGoogleServicesSettings">
+  <owner>bsazonov@chromium.org</owner>
+  <owner>jlebel@chromium.org</owner>
+  <description>
+    Recorded when a user taps in the sign-in promo in the Google services
+    settings.
   </description>
 </action>
 
@@ -17554,7 +17571,7 @@
   <owner>rogerta@chromium.org</owner>
   <owner>tienmai@chromium.org</owner>
   <description>
-    Record when a user signs in using a Windows machine's logon screen.
+    Recorded when a user signs in using a Windows machine's logon screen.
   </description>
 </action>
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 59081cae..37f8e72 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -21195,6 +21195,10 @@
   <int value="2719" label="HistoryLength"/>
   <int value="2720" label="FeaturePolicyReportOnlyHeader"/>
   <int value="2721" label="V8PaymentRequest_HasEnrolledInstrument_Method"/>
+  <int value="2722" label="TrustedTypesEnabled"/>
+  <int value="2723" label="TrustedTypesCreatePolicy"/>
+  <int value="2724" label="TrustedTypesDefaultPolicyUsed"/>
+  <int value="2725" label="TrustedTypesAssignmentError"/>
 </enum>
 
 <enum name="FeaturePolicyFeature">
@@ -21268,6 +21272,11 @@
   <int value="5" label="OpaqueRedirect"/>
 </enum>
 
+<enum name="FetchStatusWhenMatchCalled">
+  <int value="0" label="Complete"/>
+  <int value="1" label="Incomplete"/>
+</enum>
+
 <enum name="FFmpegCodecHashes">
   <int value="-2140893972" label="bfi"/>
   <int value="-2126016986" label="vp3"/>
@@ -46425,6 +46434,11 @@
   <int value="3" label="ErrorMissingUkmRecorder"/>
 </enum>
 
+<enum name="ScopeMatchCalledFrom">
+  <int value="0" label="NonDocument"/>
+  <int value="1" label="Document"/>
+</enum>
+
 <enum name="ScoutActiveExtendedReportingPref">
   <int value="0" label="Active pref is the legacy SBER pref"/>
   <int value="1" label="Active pref is the new Scout pref"/>
@@ -47679,6 +47693,7 @@
   <int value="23" label="Force signin warning"/>
   <int value="24" label="Save card bubble"/>
   <int value="25" label="Manage cards bubble"/>
+  <int value="27" label="Sync and Google services settings"/>
 </enum>
 
 <enum name="SigninAccountEquality">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 9039466..ab553f6 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -8943,6 +8943,41 @@
   </summary>
 </histogram>
 
+<histogram name="BackgroundFetch.MatchCalledFromDocumentScope"
+    enum="ScopeMatchCalledFrom" expires_after="2019-12-31">
+  <owner>nator@chromium.org</owner>
+  <owner>rayankans@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Records whether match() or matchAll() was called from Document Scope. Called
+    when match() or matchAll() is invoked in the renderer process.
+  </summary>
+</histogram>
+
+<histogram name="BackgroundFetch.MatchCalledWhenFetchIsIncomplete"
+    enum="FetchStatusWhenMatchCalled" expires_after="2019-12-31">
+  <owner>nator@chromium.org</owner>
+  <owner>rayankans@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Records whether match() or matchAll() was called when the background fetch
+    was incomplete. Called when match() or matchAll() is invoked in the renderer
+    process.
+  </summary>
+</histogram>
+
+<histogram name="BackgroundFetch.PercentOfRequestsForWhichUpdatesAreSent"
+    units="%" expires_after="2019-12-31">
+  <owner>nator@chromium.org</owner>
+  <owner>rayankans@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Records the percent of requests for which updates are received in the
+    renderer process from the browser process. Called when the completion event
+    for a background fetch has finished processing.
+  </summary>
+</histogram>
+
 <histogram name="BackgroundFetch.RegistrationCreatedError"
     enum="BackgroundFetchError">
   <obsolete>
@@ -28773,13 +28808,16 @@
 <histogram name="Event.Latency.ScrollBegin.Touch.TimeToScrollUpdateSwapBegin4"
     units="microseconds">
   <owner>tdresser@chromium.org</owner>
+  <owner>input-dev@chromium.org</owner>
+  <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
     Time between initial creation of a touch event and the start of the frame
     swap on the GPU service caused by the generated ScrollUpdate gesture event
     if that ScrollUpdate is the first such event in a given scroll gesture event
     sequence. If no swap was induced by the event, no recording is made.
 
-    Team: input-dev@chromium.org.
+    Do not modify this metric in any way without contacting
+    speed-metrics-dev@chromium.org.
 
     Warning: This metric may include reports from clients with low-resolution
     clocks (i.e. on Windows, ref. |TimeTicks::IsHighResolution()|). Such reports
@@ -29282,13 +29320,16 @@
 <histogram name="Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin4"
     units="microseconds">
   <owner>tdresser@chromium.org</owner>
+  <owner>input-dev@chromium.org</owner>
+  <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
     Time between initial creation of a touch event and start of the frame swap
     on the GPU service caused by the generated ScrollUpdate gesture event. If no
     swap was induced by the event, no recording is made. The first GSU of every
     scrolling sequence is excluded from this metric.
 
-    Team: input-dev@chromium.org.
+    Do not modify this metric in any way without contacting
+    speed-metrics-dev@chromium.org.
 
     Warning: This metric may include reports from clients with low-resolution
     clocks (i.e. on Windows, ref. |TimeTicks::IsHighResolution()|). Such reports
@@ -51476,9 +51517,13 @@
 <histogram name="Memory.Renderer.PrivateMemoryFootprint" units="MB">
   <owner>erikchen@chromium.org</owner>
   <owner>ssid@chromium.org</owner>
+  <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
     A rough estimate of the private memory footprint of the renderer process.
     Recorded once per process per UMA ping.
+
+    Do not modify this metric in any way without contacting
+    speed-metrics-dev@chromium.org.
   </summary>
 </histogram>
 
@@ -76427,9 +76472,13 @@
     name="PageLoad.Experimental.PaintTiming.NavigationToFirstMeaningfulPaint"
     units="ms">
   <owner>ksakamoto@chromium.org</owner>
+  <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
     Measures the time from navigation timing's navigation start to the first
     meaningful paint (http://bit.ly/ttfmp-doc), for main frame documents.
+
+    Do not modify this metric in any way without contacting
+    speed-metrics-dev@chromium.org.
   </summary>
 </histogram>
 
@@ -76635,11 +76684,15 @@
 
 <histogram name="PageLoad.InteractiveTiming.FirstInputDelay" units="ms">
   <owner>tdresser@chromium.org</owner>
+  <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
     Measures First Input Delay, the duration between the hardware timestamp and
     the start of event processing on the main thread for the first meaningful
     input per navigation. See https://goo.gl/tr1oTZ for a detailed explanation.
     In ms.
+
+    Do not modify this metric in any way without contacting
+    speed-metrics-dev@chromium.org.
   </summary>
 </histogram>
 
@@ -76654,9 +76707,13 @@
 
 <histogram name="PageLoad.InteractiveTiming.InputDelay" units="ms">
   <owner>tdresser@chromium.org</owner>
+  <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
     The duration between the hardware timestamp and the start of event
     processing on the main thread for a meaningful input. In ms.
+
+    Do not modify this metric in any way without contacting
+    speed-metrics-dev@chromium.org.
   </summary>
 </histogram>
 
@@ -77036,9 +77093,13 @@
 
 <histogram name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint"
     units="ms">
+  <owner>ksakamoto@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
     The time from navigation start to first &quot;contentful&quot; paint.
+
+    Do not modify this metric in any way without contacting
+    speed-metrics-dev@chromium.org.
   </summary>
 </histogram>
 
@@ -77052,10 +77113,14 @@
 </histogram>
 
 <histogram name="PageLoad.PaintTiming.NavigationToFirstPaint" units="ms">
+  <owner>ksakamoto@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
     Measures the time from navigation timing's navigation start to the time the
     first paint is performed, for main frame documents.
+
+    Do not modify this metric in any way without contacting
+    speed-metrics-dev@chromium.org.
   </summary>
 </histogram>
 
@@ -78309,6 +78374,22 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordManager.ButtonTitlePerformance.HasFormTag"
+    expires_after="2019-03-01">
+  <owner>kolos@chromium.org</owner>
+  <summary>
+    The time (ms) it takes to infer button titles within a form tag.
+  </summary>
+</histogram>
+
+<histogram name="PasswordManager.ButtonTitlePerformance.NoFormTag"
+    expires_after="2019-03-01">
+  <owner>kolos@chromium.org</owner>
+  <summary>
+    The time (ms) it takes to infer button titles outside of form tags.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.CertificateErrorsWhileSeeingForms"
     enum="PasswordCertificateError">
   <owner>battre@chromium.org</owner>
@@ -90883,11 +90964,15 @@
     units="microseconds">
   <owner>tdresser@chromium.org</owner>
   <owner>npm@chromium.org</owner>
+  <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
     The estimated queueing duration which would be observed for additional high
     priority tasks posted to the RendererScheduler, in microseconds. Recorded
     for each 1000 ms window.
 
+    Do not modify this metric in any way without contacting
+    speed-metrics-dev@chromium.org.
+
     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
@@ -97966,12 +98051,16 @@
 
 <histogram name="Scheduling.Renderer.DrawInterval2" units="microseconds">
   <owner>brianderson@chromium.org</owner>
+  <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
     The time delta between the draw times of back-to-back BeginImplFrames,
     regardless of whether or not they result in a swap.
 
     The interval is only recorded when every BeginImplFrame wants to draw.
 
+    Do not modify this metric in any way without contacting
+    speed-metrics-dev@chromium.org.
+
     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
diff --git a/tools/perf/core/stacktrace_unittest.py b/tools/perf/core/stacktrace_unittest.py
index 258e0b1..28a23f86 100644
--- a/tools/perf/core/stacktrace_unittest.py
+++ b/tools/perf/core/stacktrace_unittest.py
@@ -32,8 +32,9 @@
   # Some platforms do not support full stack traces, this test requires only
   # minimal symbols to be available.
   # Disabled on win due to crbug.com/706328.
-  @decorators.Enabled('mac', 'linux')
-  @decorators.Disabled('snowleopard', 'win')
+  # Disabled on mac, flaky: https://crbug.com/820282.
+  @decorators.Enabled('linux')
+  @decorators.Disabled('mac', 'win')
   def testCrashMinimalSymbols(self):
     with self.assertRaises(exceptions.DevtoolsTargetCrashException) as c:
       self._tab.Navigate('chrome://crash', timeout=5)
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index a4c2b3c1..b6e4df28 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -350,7 +350,6 @@
 crbug.com/839470 [ Win ] v8.browsing_desktop-future/browse:social:twitter_infinite_scroll [ Skip ]
 crbug.com/854239 [ Linux ] v8.browsing_desktop-future/browse:social:twitter_infinite_scroll [ Skip ]
 crbug.com/854203 [ Win ] v8.browsing_desktop-future/browse:news:nytimes [ Skip ]
-crbug.com/860847 [ Win ] v8.browsing_desktop-future/browse:news:reddit [ Skip ]
 crbug.com/773084 [ Mac ] v8.browsing_desktop-future/browse:tools:maps [ Skip ]
 crbug.com/906654 [ All ] v8.browsing_desktop-future/browse:media:pinterest [ Skip ]
 crbug.com/906654 [ All ] v8.browsing_desktop-future/browse:media:tumblr [ Skip ]
diff --git a/tools/perf/page_sets/dual_browser_story.py b/tools/perf/page_sets/dual_browser_story.py
index c5d1878..cd97cd7f 100644
--- a/tools/perf/page_sets/dual_browser_story.py
+++ b/tools/perf/page_sets/dual_browser_story.py
@@ -146,10 +146,12 @@
     """
     if self._browsers_created:
       return
+    self.platform.FlushDnsCache()
     for browser_type in self._browsers:
       possible_browser, browser_options = self._possible_browsers[browser_type]
       possible_browser.SetUpEnvironment(browser_options)
-      self._browsers[browser_type] = possible_browser.Create()
+      possible_browser.FlushOsPageCaches()
+      self._browsers[browser_type] = possible_browser.Create(clear_caches=False)
     self._browsers_created = True
 
   def _CloseAllBrowsers(self):
diff --git a/ui/accessibility/ax_table_info.h b/ui/accessibility/ax_table_info.h
index 3929109..005a4a4 100644
--- a/ui/accessibility/ax_table_info.h
+++ b/ui/accessibility/ax_table_info.h
@@ -84,7 +84,7 @@
   std::unordered_map<int32_t, int32_t> cell_id_to_index;
 
   // Map from each row's node ID to its row index.
-  base::hash_map<int32_t, int32_t> row_id_to_index;
+  std::unordered_map<int32_t, int32_t> row_id_to_index;
 
   // The ARIA row count and column count, if any ARIA table or grid
   // attributes are used in the table at all.
diff --git a/ui/base/resource/resource_bundle.h b/ui/base/resource/resource_bundle.h
index c24fcf0..de38284 100644
--- a/ui/base/resource/resource_bundle.h
+++ b/ui/base/resource/resource_bundle.h
@@ -10,6 +10,7 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 #include "base/containers/hash_tables.h"
@@ -324,7 +325,7 @@
 
   struct FontKey;
 
-  using IdToStringMap = base::hash_map<int, base::string16>;
+  using IdToStringMap = std::unordered_map<int, base::string16>;
 
   // Ctor/dtor are private, since we're a singleton.
   explicit ResourceBundle(Delegate* delegate);