diff --git a/DEPS b/DEPS
index cbefd23..85ce8fb0 100644
--- a/DEPS
+++ b/DEPS
@@ -116,11 +116,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': '01979132133e474427a5e615cb05d9e203ae676e',
+  'skia_revision': 'e7b1a13a1e2ae07cd53144bc979184118f1a852e',
   # 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': '55d0017cb7b12de4a2f397b60db5b94747a29eb7',
+  'v8_revision': '558ce607b922e7ac06ac3147a90a38b5266f5241',
   # 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.
@@ -176,7 +176,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': 'b81a9c76c982129c6ec624367bcb0c0dca4a49d3',
+  'catapult_revision': '352a0e0997b945a08a0c0b25e600fec59ed9ce22',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -240,7 +240,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': '69b44ee6a1269afb5c7622189de236af0c4ec2a7',
+  'dawn_revision': '391c8a9224e5bf02690722c06973af8427bdaa6b',
 }
 
 # Only these hosts are allowed for dependencies in this DEPS file.
@@ -572,7 +572,7 @@
     Var('dawn_git') + '/dawn.git' + '@' +  Var('dawn_revision'),
 
   'src/third_party/glfw/src':
-    Var('chromium_git') + '/external/github.com/glfw/glfw.git@' +  '096efdf798896cff80a0b2db08d7398b703406fe',
+    Var('chromium_git') + '/external/github.com/glfw/glfw.git@' +  '2de2589f910b1a85905f425be4d32f33cec092df',
 
   'src/third_party/apache-portable-runtime/src': {
       'url': Var('chromium_git') + '/external/apache-portable-runtime.git' + '@' + 'c3f11fcd86b42922834cae91103cf068246c6bb6',
@@ -680,7 +680,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c6ffd7af7d84ec354a92a0dc11613ec23cf82c60',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'af3328fc7a75c5462e2d0078b9d59b0a5e5e90c1',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1014,7 +1014,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'acedb7bc166fb805a037507253e935f3ea0fd0f9',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'e867072a2353e9609710c7ee0af14a954d21e397',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1166,7 +1166,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '5b6cbd789b9b91b4e46dde883c9f2ecb31eddade',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '179a3923b9e402f427728d52b3024a3de1696a66',
+    Var('webrtc_git') + '/src.git' + '@' + '72bba625d5f79f26ca75984d7acbc7ece0468a84',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1197,7 +1197,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ecb09be231577259e1472cf7d3e397faa7ac2a35',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e86231b9da1a598d910364855eb070457bebf606',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/wm/window_transient_descendant_iterator.h b/ash/wm/window_transient_descendant_iterator.h
index 9b49594..6541cb3 100644
--- a/ash/wm/window_transient_descendant_iterator.h
+++ b/ash/wm/window_transient_descendant_iterator.h
@@ -64,10 +64,10 @@
   const WindowTransientDescendantIterator& end() const { return end_; }
 
  private:
-  // Explicit assignment operator defined because an explicit copy constructor
-  // is needed and therefore the DISALLOW_COPY_AND_ASSIGN macro cannot be used.
+  // Because the explicit copy constructor is needed, explicitly delete the
+  // assignment operator rather than using DISALLOW_COPY_AND_ASSIGN.
   WindowTransientDescendantIteratorRange& operator=(
-      const WindowTransientDescendantIteratorRange& other) = default;
+      const WindowTransientDescendantIteratorRange& other) = delete;
 
   WindowTransientDescendantIterator begin_;
   WindowTransientDescendantIterator end_;
diff --git a/base/allocator/partition_allocator/page_allocator_internals_win.h b/base/allocator/partition_allocator/page_allocator_internals_win.h
index 3489132..4ef9b23 100644
--- a/base/allocator/partition_allocator/page_allocator_internals_win.h
+++ b/base/allocator/partition_allocator/page_allocator_internals_win.h
@@ -80,10 +80,18 @@
     size_t length,
     PageAccessibilityConfiguration accessibility) {
   if (accessibility == PageInaccessible) {
-    CHECK_NE(0, VirtualFree(address, length, MEM_DECOMMIT));
+    if (!VirtualFree(address, length, MEM_DECOMMIT)) {
+      // We check `GetLastError` for `ERROR_SUCCESS` here so that in a crash
+      // report we get the error number.
+      CHECK_EQ(static_cast<uint32_t>(ERROR_SUCCESS), GetLastError());
+    }
   } else {
-    CHECK_NE(nullptr, VirtualAlloc(address, length, MEM_COMMIT,
-                                   GetAccessFlags(accessibility)));
+    if (!VirtualAlloc(address, length, MEM_COMMIT,
+                      GetAccessFlags(accessibility))) {
+      // We check `GetLastError` for `ERROR_SUCCESS` here so that in a crash
+      // report we get the error number.
+      CHECK_EQ(static_cast<uint32_t>(ERROR_SUCCESS), GetLastError());
+    }
   }
 }
 
diff --git a/base/android/application_status_listener_unittest.cc b/base/android/application_status_listener_unittest.cc
index 37e8e1c..f904dd0 100644
--- a/base/android/application_status_listener_unittest.cc
+++ b/base/android/application_status_listener_unittest.cc
@@ -9,9 +9,9 @@
 #include "base/bind.h"
 #include "base/callback_forward.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -45,8 +45,7 @@
       : state_(kInvalidApplicationState),
         event_(WaitableEvent::ResetPolicy::AUTOMATIC,
                WaitableEvent::InitialState::NOT_SIGNALED),
-        thread_("ApplicationStatusTest thread"),
-        main_() {}
+        thread_("ApplicationStatusTest thread") {}
 
   void Run() {
     // Start the thread and tell it to register for events.
@@ -93,14 +92,14 @@
   ApplicationState state_;
   base::WaitableEvent event_;
   base::Thread thread_;
-  base::MessageLoop main_;
+  test::ScopedTaskEnvironment scoped_task_environment_;
   std::unique_ptr<ApplicationStatusListener> listener_;
 };
 
 }  // namespace
 
 TEST(ApplicationStatusListenerTest, SingleThread) {
-  MessageLoop message_loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
 
   ApplicationState result = kInvalidApplicationState;
 
diff --git a/base/cancelable_callback_unittest.cc b/base/cancelable_callback_unittest.cc
index 42e753f..0c254a8 100644
--- a/base/cancelable_callback_unittest.cc
+++ b/base/cancelable_callback_unittest.cc
@@ -10,9 +10,9 @@
 #include "base/bind_helpers.h"
 #include "base/location.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -166,10 +166,10 @@
   EXPECT_TRUE(cancelable.IsCancelled());
 }
 
-// CancelableCallback posted to a MessageLoop with PostTask.
-//  - Callbacks posted to a MessageLoop can be cancelled.
+// CancelableCallback posted to a task environment with PostTask.
+//  - Posted callbacks can be cancelled.
 TEST(CancelableCallbackTest, PostTask) {
-  MessageLoop loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
 
   int count = 0;
   CancelableClosure cancelable(base::Bind(&Increment,
@@ -182,7 +182,7 @@
 
   ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
 
-  // Cancel before running the message loop.
+  // Cancel before running the tasks.
   cancelable.Cancel();
   RunLoop().RunUntilIdle();
 
diff --git a/base/debug/task_annotator_unittest.cc b/base/debug/task_annotator_unittest.cc
index 70e327c2..c85edfdc 100644
--- a/base/debug/task_annotator_unittest.cc
+++ b/base/debug/task_annotator_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/pending_task.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
@@ -134,7 +133,7 @@
 
 // Ensure the task backtrace populates correctly.
 TEST_F(TaskAnnotatorBacktraceIntegrationTest, SingleThreadedSimple) {
-  MessageLoop loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
   const Location location0 = FROM_HERE;
   const Location location1 = FROM_HERE;
   const Location location2 = FROM_HERE;
@@ -148,7 +147,7 @@
   // last 4 parents are kept).
   OnceClosure task5 = BindOnce(
       &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
-      Unretained(this), loop.task_runner(), location5, FROM_HERE,
+      Unretained(this), ThreadTaskRunnerHandle::Get(), location5, FROM_HERE,
       ExpectedTrace({location4.program_counter(), location3.program_counter(),
                      location2.program_counter(), location1.program_counter()}),
       run_loop.QuitClosure());
@@ -156,31 +155,31 @@
   // Task i=4/3/2/1/0 have tasks [0,i) as parents.
   OnceClosure task4 = BindOnce(
       &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
-      Unretained(this), loop.task_runner(), location4, location5,
+      Unretained(this), ThreadTaskRunnerHandle::Get(), location4, location5,
       ExpectedTrace({location3.program_counter(), location2.program_counter(),
                      location1.program_counter(), location0.program_counter()}),
       std::move(task5));
   OnceClosure task3 = BindOnce(
       &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
-      Unretained(this), loop.task_runner(), location3, location4,
+      Unretained(this), ThreadTaskRunnerHandle::Get(), location3, location4,
       ExpectedTrace({location2.program_counter(), location1.program_counter(),
                      location0.program_counter()}),
       std::move(task4));
   OnceClosure task2 = BindOnce(
       &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
-      Unretained(this), loop.task_runner(), location2, location3,
+      Unretained(this), ThreadTaskRunnerHandle::Get(), location2, location3,
       ExpectedTrace({location1.program_counter(), location0.program_counter()}),
       std::move(task3));
-  OnceClosure task1 =
-      BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
-               Unretained(this), loop.task_runner(), location1, location2,
-               ExpectedTrace({location0.program_counter()}), std::move(task2));
+  OnceClosure task1 = BindOnce(
+      &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
+      Unretained(this), ThreadTaskRunnerHandle::Get(), location1, location2,
+      ExpectedTrace({location0.program_counter()}), std::move(task2));
   OnceClosure task0 =
       BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
-               Unretained(this), loop.task_runner(), location0, location1,
-               ExpectedTrace({}), std::move(task1));
+               Unretained(this), ThreadTaskRunnerHandle::Get(), location0,
+               location1, ExpectedTrace({}), std::move(task1));
 
-  loop.task_runner()->PostTask(location0, std::move(task0));
+  ThreadTaskRunnerHandle::Get()->PostTask(location0, std::move(task0));
 
   run_loop.Run();
 }
@@ -189,7 +188,7 @@
 TEST_F(TaskAnnotatorBacktraceIntegrationTest, MultipleThreads) {
   test::ScopedTaskEnvironment scoped_task_environment;
 
-  // Use diverse task runners (a MessageLoop on the main thread, a TaskScheduler
+  // Use diverse task runners (a task environment main thread, a TaskScheduler
   // based SequencedTaskRunner, and a TaskScheduler based
   // SingleThreadTaskRunner) to verify that TaskAnnotator can capture backtraces
   // for PostTasks back-and-forth between these.
@@ -278,7 +277,7 @@
 
 // Ensure nesting doesn't break the chain.
 TEST_F(TaskAnnotatorBacktraceIntegrationTest, SingleThreadedNested) {
-  MessageLoop loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
   const Location location0 = FROM_HERE;
   const Location location1 = FROM_HERE;
   const Location location2 = FROM_HERE;
@@ -315,19 +314,19 @@
   // 4.
   OnceClosure task5 = BindOnce(
       &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
-      Unretained(this), loop.task_runner(), location5, FROM_HERE,
+      Unretained(this), ThreadTaskRunnerHandle::Get(), location5, FROM_HERE,
       ExpectedTrace({location4.program_counter(), location3.program_counter(),
                      location2.program_counter(), location1.program_counter()}),
       run_loop.QuitClosure());
   OnceClosure task4 = BindOnce(
       &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
-      Unretained(this), loop.task_runner(), location4, location5,
+      Unretained(this), ThreadTaskRunnerHandle::Get(), location4, location5,
       ExpectedTrace({location3.program_counter(), location2.program_counter(),
                      location1.program_counter(), location0.program_counter()}),
       std::move(task5));
   OnceClosure task3 = BindOnce(
       &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
-      Unretained(this), loop.task_runner(), location3, location4,
+      Unretained(this), ThreadTaskRunnerHandle::Get(), location3, location4,
       ExpectedTrace({location2.program_counter(), location1.program_counter(),
                      location0.program_counter()}),
       std::move(task4));
@@ -338,7 +337,7 @@
 
   OnceClosure task2 = BindOnce(
       &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
-      Unretained(this), loop.task_runner(), location2, location3,
+      Unretained(this), ThreadTaskRunnerHandle::Get(), location2, location3,
       ExpectedTrace({location1.program_counter(), location0.program_counter()}),
       std::move(run_task_3_then_quit_nested_loop1));
 
@@ -357,11 +356,11 @@
 
   OnceClosure task0 =
       BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
-               Unretained(this), loop.task_runner(), location0, location1,
-               ExpectedTrace({}), std::move(task1));
+               Unretained(this), ThreadTaskRunnerHandle::Get(), location0,
+               location1, ExpectedTrace({}), std::move(task1));
 
-  loop.task_runner()->PostTask(location0, std::move(task0));
-  loop.task_runner()->PostTask(
+  ThreadTaskRunnerHandle::Get()->PostTask(location0, std::move(task0));
+  ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, BindOnce(&RunLoop::Run, Unretained(&nested_run_loop1)));
 
   run_loop.Run();
diff --git a/base/deferred_sequenced_task_runner_unittest.cc b/base/deferred_sequenced_task_runner_unittest.cc
index 5cb220f..ce92392 100644
--- a/base/deferred_sequenced_task_runner_unittest.cc
+++ b/base/deferred_sequenced_task_runner_unittest.cc
@@ -9,10 +9,11 @@
 #include "base/callback_forward.h"
 #include "base/location.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -56,10 +57,10 @@
 
  protected:
   DeferredSequencedTaskRunnerTest()
-      : loop_(),
-        runner_(new DeferredSequencedTaskRunner(loop_.task_runner())) {}
+      : runner_(
+            new DeferredSequencedTaskRunner(ThreadTaskRunnerHandle::Get())) {}
 
-  MessageLoop loop_;
+  test::ScopedTaskEnvironment scoped_task_environment_;
   scoped_refptr<DeferredSequencedTaskRunner> runner_;
   mutable Lock lock_;
   std::vector<int> executed_task_ids_;
@@ -205,7 +206,7 @@
                          std::move(quit_closure).Run();
                        },
                        &run_called, run_loop.QuitClosure()));
-  runner->StartWithTaskRunner(loop_.task_runner());
+  runner->StartWithTaskRunner(ThreadTaskRunnerHandle::Get());
   run_loop.Run();
   EXPECT_TRUE(run_called);
 }
diff --git a/base/files/file_path_watcher_unittest.cc b/base/files/file_path_watcher_unittest.cc
index 42121389..abc4bd44 100644
--- a/base/files/file_path_watcher_unittest.cc
+++ b/base/files/file_path_watcher_unittest.cc
@@ -21,12 +21,12 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/location.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/test/test_file_util.h"
 #include "base/test/test_timeouts.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -47,12 +47,12 @@
 
 class TestDelegate;
 
-// Aggregates notifications from the test delegates and breaks the message loop
+// Aggregates notifications from the test delegates and breaks the run loop
 // the test thread is waiting on once they all came in.
 class NotificationCollector
     : public base::RefCountedThreadSafe<NotificationCollector> {
  public:
-  NotificationCollector() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
+  NotificationCollector() : task_runner_(ThreadTaskRunnerHandle::Get()) {}
 
   // Called from the file thread by the delegates.
   void OnChange(TestDelegate* delegate) {
@@ -143,7 +143,8 @@
  public:
   FilePathWatcherTest()
 #if defined(OS_POSIX)
-      : file_descriptor_watcher_(loop_.task_runner())
+      : scoped_task_environment_(
+            test::ScopedTaskEnvironment::MainThreadType::IO)
 #endif
   {
   }
@@ -204,10 +205,7 @@
 
   NotificationCollector* collector() { return collector_.get(); }
 
-  MessageLoopForIO loop_;
-#if defined(OS_POSIX)
-  FileDescriptorWatcher file_descriptor_watcher_;
-#endif
+  test::ScopedTaskEnvironment scoped_task_environment_;
 
   ScopedTempDir temp_dir_;
   scoped_refptr<NotificationCollector> collector_;
diff --git a/base/files/file_proxy_unittest.cc b/base/files/file_proxy_unittest.cc
index cb689db2f..27db2f6f 100644
--- a/base/files/file_proxy_unittest.cc
+++ b/base/files/file_proxy_unittest.cc
@@ -15,8 +15,8 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
@@ -27,7 +27,9 @@
 class FileProxyTest : public testing::Test {
  public:
   FileProxyTest()
-      : file_thread_("FileProxyTestFileThread"),
+      : scoped_task_environment_(
+            test::ScopedTaskEnvironment::MainThreadType::IO),
+        file_thread_("FileProxyTestFileThread"),
         error_(File::FILE_OK),
         bytes_written_(-1),
         weak_factory_(this) {}
@@ -93,7 +95,7 @@
   const FilePath TestPath() const { return dir_.GetPath().AppendASCII("test"); }
 
   ScopedTempDir dir_;
-  MessageLoopForIO message_loop_;
+  test::ScopedTaskEnvironment scoped_task_environment_;
   Thread file_thread_;
 
   File::Error error_;
diff --git a/base/files/important_file_writer_unittest.cc b/base/files/important_file_writer_unittest.cc
index 5dddc71..39e6308 100644
--- a/base/files/important_file_writer_unittest.cc
+++ b/base/files/important_file_writer_unittest.cc
@@ -13,10 +13,10 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -124,7 +124,7 @@
  protected:
   WriteCallbacksObserver write_callback_observer_;
   FilePath file_;
-  MessageLoop loop_;
+  test::ScopedTaskEnvironment scoped_task_environment_;
 
  private:
   ScopedTempDir temp_dir_;
diff --git a/base/memory/memory_pressure_listener_unittest.cc b/base/memory/memory_pressure_listener_unittest.cc
index 87d5f4c..7c095ec 100644
--- a/base/memory/memory_pressure_listener_unittest.cc
+++ b/base/memory/memory_pressure_listener_unittest.cc
@@ -5,8 +5,8 @@
 #include "base/memory/memory_pressure_listener.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace base {
@@ -15,15 +15,17 @@
 
 class MemoryPressureListenerTest : public testing::Test {
  public:
+  MemoryPressureListenerTest()
+      : scoped_task_environment_(
+            test::ScopedTaskEnvironment::MainThreadType::UI) {}
+
   void SetUp() override {
-    message_loop_.reset(new MessageLoopForUI());
     listener_.reset(new MemoryPressureListener(
         Bind(&MemoryPressureListenerTest::OnMemoryPressure, Unretained(this))));
   }
 
   void TearDown() override {
     listener_.reset();
-    message_loop_.reset();
   }
 
  protected:
@@ -47,7 +49,7 @@
   MOCK_METHOD1(OnMemoryPressure,
                void(MemoryPressureListener::MemoryPressureLevel));
 
-  std::unique_ptr<MessageLoopForUI> message_loop_;
+  test::ScopedTaskEnvironment scoped_task_environment_;
   std::unique_ptr<MemoryPressureListener> listener_;
 };
 
diff --git a/base/memory/memory_pressure_monitor_chromeos_unittest.cc b/base/memory/memory_pressure_monitor_chromeos_unittest.cc
index db715b4..8ac11334 100644
--- a/base/memory/memory_pressure_monitor_chromeos_unittest.cc
+++ b/base/memory/memory_pressure_monitor_chromeos_unittest.cc
@@ -6,9 +6,9 @@
 
 #include "base/macros.h"
 #include "base/memory/memory_pressure_listener.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/system/sys_info.h"
+#include "base/test/scoped_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -79,7 +79,8 @@
   if (base::SysInfo::IsRunningOnChromeOS())
     return;
 
-  base::MessageLoopForUI message_loop;
+  test::ScopedTaskEnvironment scoped_task_environment(
+      test::ScopedTaskEnvironment::MainThreadType::UI);
   std::unique_ptr<TestMemoryPressureMonitor> monitor(
       new TestMemoryPressureMonitor);
   std::unique_ptr<MemoryPressureListener> listener(
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
index 0b861bb..dce2dd6 100644
--- a/base/metrics/field_trial_unittest.cc
+++ b/base/metrics/field_trial_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/field_trial_param_associator.h"
 #include "base/rand_util.h"
 #include "base/run_loop.h"
@@ -21,6 +20,7 @@
 #include "base/test/mock_entropy_provider.h"
 #include "base/test/multiprocess_test.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/test/test_shared_memory_util.h"
 #include "base/test/test_timeouts.h"
 #include "build/build_config.h"
@@ -107,7 +107,7 @@
   FieldTrialTest() : trial_list_(nullptr) {}
 
  private:
-  MessageLoop message_loop_;
+  test::ScopedTaskEnvironment scoped_task_environment_;
   FieldTrialList trial_list_;
 
   DISALLOW_COPY_AND_ASSIGN(FieldTrialTest);
diff --git a/base/observer_list_threadsafe_unittest.cc b/base/observer_list_threadsafe_unittest.cc
index 3134fca7..00ca1cf 100644
--- a/base/observer_list_threadsafe_unittest.cc
+++ b/base/observer_list_threadsafe_unittest.cc
@@ -165,7 +165,7 @@
 }  // namespace
 
 TEST(ObserverListThreadSafeTest, BasicTest) {
-  MessageLoop loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
 
   scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
       new ObserverListThreadSafe<Foo>);
@@ -194,7 +194,7 @@
 }
 
 TEST(ObserverListThreadSafeTest, RemoveObserver) {
-  MessageLoop loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
 
   scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
       new ObserverListThreadSafe<Foo>);
@@ -237,7 +237,7 @@
 
   {
     // Add c when there's a sequence.
-    MessageLoop loop;
+    test::ScopedTaskEnvironment scoped_task_environment;
     observer_list->AddObserver(&c);
 
     observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
@@ -266,7 +266,7 @@
   observer_list->RemoveObserver(&a);
 
   // Notifying should not fail but should also be a no-op.
-  MessageLoop loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
   observer_list->AddObserver(&b);
   observer_list->Notify(FROM_HERE, &Foo::Observe, 30);
   RunLoop().RunUntilIdle();
@@ -297,7 +297,7 @@
 };
 
 TEST(ObserverListThreadSafeTest, RemoveMultipleObservers) {
-  MessageLoop loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
   scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
       new ObserverListThreadSafe<Foo>);
 
@@ -320,7 +320,7 @@
 // observer threads will also trigger notifications to all observers.
 static void ThreadSafeObserverHarness(int num_threads,
                                       bool cross_thread_notifies) {
-  MessageLoop loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
 
   scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
       new ObserverListThreadSafe<Foo>);
@@ -347,8 +347,8 @@
   ASSERT_EQ(static_cast<size_t>(num_threads), threaded_observer.size());
   ASSERT_EQ(static_cast<size_t>(num_threads), ready.size());
 
-  // This makes sure that threaded_observer has gotten to set loop_, so that we
-  // can call Quit() below safe-ish-ly.
+  // This makes sure that threaded_observer has gotten to set
+  // scoped_task_environment_, so that we can call Quit() below safe-ish-ly.
   for (int i = 0; i < num_threads; ++i)
     ready[i]->Wait();
 
@@ -385,14 +385,14 @@
   ThreadSafeObserverHarness(3, true);
 }
 
-TEST(ObserverListThreadSafeTest, OutlivesMessageLoop) {
-  MessageLoop* loop = new MessageLoop;
+TEST(ObserverListThreadSafeTest, OutlivesTaskEnvironment) {
+  Optional<test::ScopedTaskEnvironment> scoped_task_environment(in_place);
   scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
       new ObserverListThreadSafe<Foo>);
 
   Adder a(1);
   observer_list->AddObserver(&a);
-  delete loop;
+  scoped_task_environment.reset();
   // Test passes if we don't crash here.
   observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
 }
@@ -528,7 +528,7 @@
 
 // Same as ObserverListTest.Existing, but for ObserverListThreadSafe
 TEST(ObserverListThreadSafeTest, Existing) {
-  MessageLoop loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
   scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
       new ObserverListThreadSafe<Foo>(ObserverListPolicy::EXISTING_ONLY));
   Adder a(1);
diff --git a/base/power_monitor/power_monitor_unittest.cc b/base/power_monitor/power_monitor_unittest.cc
index 85d069b..71fb260 100644
--- a/base/power_monitor/power_monitor_unittest.cc
+++ b/base/power_monitor/power_monitor_unittest.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/power_monitor/power_monitor.h"
+#include "base/macros.h"
 #include "base/test/power_monitor_test_base.h"
+#include "base/test/scoped_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -23,7 +23,7 @@
   PowerMonitor* monitor() { return power_monitor_.get(); }
 
  private:
-  base::MessageLoop message_loop_;
+  test::ScopedTaskEnvironment scoped_task_environment_;
   PowerMonitorTestSource* power_monitor_source_;
   std::unique_ptr<PowerMonitor> power_monitor_;
 
diff --git a/base/sequenced_task_runner_unittest.cc b/base/sequenced_task_runner_unittest.cc
index 4dcc7e5a..1a6c6e9 100644
--- a/base/sequenced_task_runner_unittest.cc
+++ b/base/sequenced_task_runner_unittest.cc
@@ -8,9 +8,10 @@
 
 #include "base/bind.h"
 #include "base/gtest_prod_util.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -46,19 +47,16 @@
   SequencedTaskRunnerTest() : foreign_thread_("foreign") {}
 
   void SetUp() override {
-    main_runner_ = message_loop_.task_runner();
-
     foreign_thread_.Start();
     foreign_runner_ = foreign_thread_.task_runner();
   }
 
-  scoped_refptr<SequencedTaskRunner> main_runner_;
   scoped_refptr<SequencedTaskRunner> foreign_runner_;
 
   Thread foreign_thread_;
 
  private:
-  MessageLoop message_loop_;
+  test::ScopedTaskEnvironment scoped_task_environment_;
 
   DISALLOW_COPY_AND_ASSIGN(SequencedTaskRunnerTest);
 };
@@ -69,8 +67,8 @@
 TEST_F(SequencedTaskRunnerTest, OnTaskRunnerDeleterOnMainThread) {
   bool deleted_on_main_thread = false;
   SequenceBoundUniquePtr ptr(
-      new FlagOnDelete(&deleted_on_main_thread, main_runner_),
-      OnTaskRunnerDeleter(main_runner_));
+      new FlagOnDelete(&deleted_on_main_thread, ThreadTaskRunnerHandle::Get()),
+      OnTaskRunnerDeleter(ThreadTaskRunnerHandle::Get()));
   EXPECT_FALSE(deleted_on_main_thread);
   foreign_runner_->PostTask(
       FROM_HERE, BindOnce([](SequenceBoundUniquePtr) {}, std::move(ptr)));
@@ -86,7 +84,8 @@
 
 TEST_F(SequencedTaskRunnerTest, OnTaskRunnerDeleterTargetStoppedEarly) {
   bool deleted_on_main_thread = false;
-  FlagOnDelete* raw = new FlagOnDelete(&deleted_on_main_thread, main_runner_);
+  FlagOnDelete* raw =
+      new FlagOnDelete(&deleted_on_main_thread, ThreadTaskRunnerHandle::Get());
   SequenceBoundUniquePtr ptr(raw, OnTaskRunnerDeleter(foreign_runner_));
   EXPECT_FALSE(deleted_on_main_thread);
 
diff --git a/base/synchronization/waitable_event_watcher_unittest.cc b/base/synchronization/waitable_event_watcher_unittest.cc
index ec056eff..c1cb720 100644
--- a/base/synchronization/waitable_event_watcher_unittest.cc
+++ b/base/synchronization/waitable_event_watcher_unittest.cc
@@ -8,11 +8,12 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -20,12 +21,12 @@
 
 namespace {
 
-// The message loops on which each waitable event timer should be tested.
-const MessageLoop::Type testing_message_loops[] = {
-  MessageLoop::TYPE_DEFAULT,
-  MessageLoop::TYPE_IO,
+// The main thread types on which each waitable event should be tested.
+const test::ScopedTaskEnvironment::MainThreadType testing_main_threads[] = {
+    test::ScopedTaskEnvironment::MainThreadType::DEFAULT,
+    test::ScopedTaskEnvironment::MainThreadType::IO,
 #if !defined(OS_IOS)  // iOS does not allow direct running of the UI loop.
-  MessageLoop::TYPE_UI,
+    test::ScopedTaskEnvironment::MainThreadType::UI,
 #endif
 };
 
@@ -48,10 +49,11 @@
 }  // namespace
 
 class WaitableEventWatcherTest
-    : public testing::TestWithParam<MessageLoop::Type> {};
+    : public testing::TestWithParam<
+          test::ScopedTaskEnvironment::MainThreadType> {};
 
 TEST_P(WaitableEventWatcherTest, BasicSignalManual) {
-  MessageLoop message_loop(GetParam());
+  test::ScopedTaskEnvironment scoped_task_environment(GetParam());
 
   // A manual-reset event that is not yet signaled.
   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
@@ -69,7 +71,7 @@
 }
 
 TEST_P(WaitableEventWatcherTest, BasicSignalAutomatic) {
-  MessageLoop message_loop(GetParam());
+  test::ScopedTaskEnvironment scoped_task_environment(GetParam());
 
   WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC,
                       WaitableEvent::InitialState::NOT_SIGNALED);
@@ -87,7 +89,7 @@
 }
 
 TEST_P(WaitableEventWatcherTest, BasicCancel) {
-  MessageLoop message_loop(GetParam());
+  test::ScopedTaskEnvironment scoped_task_environment(GetParam());
 
   // A manual-reset event that is not yet signaled.
   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
@@ -102,7 +104,7 @@
 }
 
 TEST_P(WaitableEventWatcherTest, CancelAfterSet) {
-  MessageLoop message_loop(GetParam());
+  test::ScopedTaskEnvironment scoped_task_environment(GetParam());
 
   // A manual-reset event that is not yet signaled.
   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
@@ -130,8 +132,8 @@
   EXPECT_EQ(1, counter);
 }
 
-TEST_P(WaitableEventWatcherTest, OutlivesMessageLoop) {
-  // Simulate a MessageLoop that dies before an WaitableEventWatcher.  This
+TEST_P(WaitableEventWatcherTest, OutlivesTaskEnvironment) {
+  // Simulate a task environment that dies before an WaitableEventWatcher.  This
   // ordinarily doesn't happen when people use the Thread class, but it can
   // happen when people use the Singleton pattern or atexit.
   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
@@ -139,7 +141,7 @@
   {
     std::unique_ptr<WaitableEventWatcher> watcher;
     {
-      MessageLoop message_loop(GetParam());
+      test::ScopedTaskEnvironment scoped_task_environment(GetParam());
       watcher = std::make_unique<WaitableEventWatcher>();
 
       watcher->StartWatching(&event, BindOnce(&QuitWhenSignaled),
@@ -149,7 +151,7 @@
 }
 
 TEST_P(WaitableEventWatcherTest, SignaledAtStartManual) {
-  MessageLoop message_loop(GetParam());
+  test::ScopedTaskEnvironment scoped_task_environment(GetParam());
 
   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
                       WaitableEvent::InitialState::SIGNALED);
@@ -164,7 +166,7 @@
 }
 
 TEST_P(WaitableEventWatcherTest, SignaledAtStartAutomatic) {
-  MessageLoop message_loop(GetParam());
+  test::ScopedTaskEnvironment scoped_task_environment(GetParam());
 
   WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC,
                       WaitableEvent::InitialState::SIGNALED);
@@ -180,7 +182,7 @@
 }
 
 TEST_P(WaitableEventWatcherTest, StartWatchingInCallback) {
-  MessageLoop message_loop(GetParam());
+  test::ScopedTaskEnvironment scoped_task_environment(GetParam());
 
   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
                       WaitableEvent::InitialState::NOT_SIGNALED);
@@ -204,7 +206,7 @@
 }
 
 TEST_P(WaitableEventWatcherTest, MultipleWatchersManual) {
-  MessageLoop message_loop(GetParam());
+  test::ScopedTaskEnvironment scoped_task_environment(GetParam());
 
   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
                       WaitableEvent::InitialState::NOT_SIGNALED);
@@ -239,7 +241,7 @@
 
 // Tests that only one async waiter gets called back for an auto-reset event.
 TEST_P(WaitableEventWatcherTest, MultipleWatchersAutomatic) {
-  MessageLoop message_loop(GetParam());
+  test::ScopedTaskEnvironment scoped_task_environment(GetParam());
 
   WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC,
                       WaitableEvent::InitialState::NOT_SIGNALED);
@@ -299,17 +301,18 @@
 // To help detect errors around deleting WaitableEventWatcher, an additional
 // bool parameter is used to test sleeping between watching and deletion.
 class WaitableEventWatcherDeletionTest
-    : public testing::TestWithParam<std::tuple<MessageLoop::Type, bool>> {};
+    : public testing::TestWithParam<
+          std::tuple<test::ScopedTaskEnvironment::MainThreadType, bool>> {};
 
 TEST_P(WaitableEventWatcherDeletionTest, DeleteUnder) {
-  MessageLoop::Type message_loop_type;
+  test::ScopedTaskEnvironment::MainThreadType main_thread_type;
   bool delay_after_delete;
-  std::tie(message_loop_type, delay_after_delete) = GetParam();
+  std::tie(main_thread_type, delay_after_delete) = GetParam();
 
   // Delete the WaitableEvent out from under the Watcher. This is explictly
   // allowed by the interface.
 
-  MessageLoop message_loop(message_loop_type);
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   {
     WaitableEventWatcher watcher;
@@ -334,13 +337,13 @@
 }
 
 TEST_P(WaitableEventWatcherDeletionTest, SignalAndDelete) {
-  MessageLoop::Type message_loop_type;
+  test::ScopedTaskEnvironment::MainThreadType main_thread_type;
   bool delay_after_delete;
-  std::tie(message_loop_type, delay_after_delete) = GetParam();
+  std::tie(main_thread_type, delay_after_delete) = GetParam();
 
   // Signal and immediately delete the WaitableEvent out from under the Watcher.
 
-  MessageLoop message_loop(message_loop_type);
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   {
     WaitableEventWatcher watcher;
@@ -371,13 +374,13 @@
 // Tests deleting the WaitableEventWatcher between signaling the event and
 // when the callback should be run.
 TEST_P(WaitableEventWatcherDeletionTest, DeleteWatcherBeforeCallback) {
-  MessageLoop::Type message_loop_type;
+  test::ScopedTaskEnvironment::MainThreadType main_thread_type;
   bool delay_after_delete;
-  std::tie(message_loop_type, delay_after_delete) = GetParam();
+  std::tie(main_thread_type, delay_after_delete) = GetParam();
 
-  MessageLoop message_loop(message_loop_type);
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
   scoped_refptr<SingleThreadTaskRunner> task_runner =
-      message_loop.task_runner();
+      ThreadTaskRunnerHandle::Get();
 
   // Flag used to esnure that the |watcher_callback| never runs.
   bool did_callback = false;
@@ -418,12 +421,11 @@
 
 INSTANTIATE_TEST_CASE_P(,
                         WaitableEventWatcherTest,
-                        testing::ValuesIn(testing_message_loops));
+                        testing::ValuesIn(testing_main_threads));
 
 INSTANTIATE_TEST_CASE_P(
     ,
     WaitableEventWatcherDeletionTest,
-    testing::Combine(testing::ValuesIn(testing_message_loops),
-                     testing::Bool()));
+    testing::Combine(testing::ValuesIn(testing_main_threads), testing::Bool()));
 
 }  // namespace base
diff --git a/base/system/system_monitor_unittest.cc b/base/system/system_monitor_unittest.cc
index f4ef68f..912a5d4 100644
--- a/base/system/system_monitor_unittest.cc
+++ b/base/system/system_monitor_unittest.cc
@@ -5,9 +5,9 @@
 #include "base/system/system_monitor.h"
 
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/test/mock_devices_changed_observer.h"
+#include "base/test/scoped_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -19,7 +19,7 @@
  protected:
   SystemMonitorTest() { system_monitor_.reset(new SystemMonitor); }
 
-  MessageLoop message_loop_;
+  test::ScopedTaskEnvironment scoped_task_environment_;
   std::unique_ptr<SystemMonitor> system_monitor_;
 
  private:
diff --git a/base/task/cancelable_task_tracker_unittest.cc b/base/task/cancelable_task_tracker_unittest.cc
index c75adc4b..76032d94 100644
--- a/base/task/cancelable_task_tracker_unittest.cc
+++ b/base/task/cancelable_task_tracker_unittest.cc
@@ -12,10 +12,10 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/test/gtest_util.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -37,7 +37,7 @@
 
  private:
   // Needed by CancelableTaskTracker methods.
-  MessageLoop message_loop_;
+  test::ScopedTaskEnvironment scoped_task_environment_;
 };
 
 void AddFailureAt(const Location& location) {
diff --git a/base/task/sequence_manager/sequence_manager_perftest.cc b/base/task/sequence_manager/sequence_manager_perftest.cc
index 7e5ec20..791e4d6 100644
--- a/base/task/sequence_manager/sequence_manager_perftest.cc
+++ b/base/task/sequence_manager/sequence_manager_perftest.cc
@@ -11,6 +11,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/message_loop/message_pump_default.h"
 #include "base/run_loop.h"
+#include "base/sequence_checker.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/condition_variable.h"
@@ -288,13 +289,17 @@
         num_tasks_(num_tasks),
         task_closure_(
             BindRepeating(&SameThreadTaskSource::TestTask, Unretained(this))),
-        task_runners_(std::move(task_runners)) {}
+        task_runners_(std::move(task_runners)) {
+    DETACH_FROM_SEQUENCE(sequence_checker_);
+  }
 
   void Start() override {
     num_tasks_in_flight_ = 1;
     num_tasks_to_post_ = num_tasks_;
     num_tasks_to_run_ = num_tasks_;
-    TestTask();
+    // Post the initial task instead of running it synchronously to ensure that
+    // all invocations happen on the same sequence.
+    PostTask(0);
   }
 
  protected:
@@ -303,6 +308,8 @@
   virtual void SignalDone() = 0;
 
   void TestTask() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
     if (--num_tasks_to_run_ == 0) {
       SignalDone();
       return;
@@ -340,6 +347,7 @@
   unsigned int num_tasks_in_flight_;
   unsigned int num_tasks_to_post_;
   unsigned int num_tasks_to_run_;
+  SEQUENCE_CHECKER(sequence_checker_);
 };
 
 class CrossThreadTaskSource : public TaskSource {
diff --git a/base/task_runner_util_unittest.cc b/base/task_runner_util_unittest.cc
index c6d4997..9c1ed1f 100644
--- a/base/task_runner_util_unittest.cc
+++ b/base/task_runner_util_unittest.cc
@@ -8,8 +8,9 @@
 
 #include "base/bind.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -85,8 +86,8 @@
 TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResult) {
   int result = 0;
 
-  MessageLoop message_loop;
-  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+  test::ScopedTaskEnvironment scoped_task_environment;
+  PostTaskAndReplyWithResult(ThreadTaskRunnerHandle::Get().get(), FROM_HERE,
                              BindOnce(&ReturnFourtyTwo),
                              BindOnce(&StoreValue, &result));
 
@@ -98,8 +99,8 @@
 TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultImplicitConvert) {
   double result = 0;
 
-  MessageLoop message_loop;
-  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+  test::ScopedTaskEnvironment scoped_task_environment;
+  PostTaskAndReplyWithResult(ThreadTaskRunnerHandle::Get().get(), FROM_HERE,
                              BindOnce(&ReturnFourtyTwo),
                              BindOnce(&StoreDoubleValue, &result));
 
@@ -112,8 +113,8 @@
   g_foo_destruct_count = 0;
   g_foo_free_count = 0;
 
-  MessageLoop message_loop;
-  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+  test::ScopedTaskEnvironment scoped_task_environment;
+  PostTaskAndReplyWithResult(ThreadTaskRunnerHandle::Get().get(), FROM_HERE,
                              BindOnce(&CreateFoo), BindOnce(&ExpectFoo));
 
   RunLoop().RunUntilIdle();
@@ -126,8 +127,8 @@
   g_foo_destruct_count = 0;
   g_foo_free_count = 0;
 
-  MessageLoop message_loop;
-  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+  test::ScopedTaskEnvironment scoped_task_environment;
+  PostTaskAndReplyWithResult(ThreadTaskRunnerHandle::Get().get(), FROM_HERE,
                              BindOnce(&CreateScopedFoo),
                              BindOnce(&ExpectScopedFoo));
 
@@ -141,10 +142,10 @@
      PostTaskAndReplyWithResultWithoutDefaultConstructor) {
   const int kSomeVal = 17;
 
-  MessageLoop message_loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
   int actual = 0;
   PostTaskAndReplyWithResult(
-      message_loop.task_runner().get(), FROM_HERE,
+      ThreadTaskRunnerHandle::Get().get(), FROM_HERE,
       BindOnce(&CreateFooWithoutDefaultConstructor, kSomeVal),
       BindOnce(&SaveFooWithoutDefaultConstructor, &actual));
 
diff --git a/base/threading/sequenced_task_runner_handle_unittest.cc b/base/threading/sequenced_task_runner_handle_unittest.cc
index de54d91..00d21b8 100644
--- a/base/threading/sequenced_task_runner_handle_unittest.cc
+++ b/base/threading/sequenced_task_runner_handle_unittest.cc
@@ -52,7 +52,7 @@
   base::test::ScopedTaskEnvironment scoped_task_environment_;
 };
 
-TEST_F(SequencedTaskRunnerHandleTest, FromMessageLoop) {
+TEST_F(SequencedTaskRunnerHandleTest, FromTaskEnvironment) {
   VerifyCurrentSequencedTaskRunner();
   RunLoop().RunUntilIdle();
 }
@@ -72,7 +72,7 @@
   scoped_task_environment_.RunUntilIdle();
 }
 
-TEST(SequencedTaskRunnerHandleTestWithoutMessageLoop, FromHandleInScope) {
+TEST(SequencedTaskRunnerHandleTestWithoutTaskEnvironment, FromHandleInScope) {
   scoped_refptr<SequencedTaskRunner> test_task_runner(new TestSimpleTaskRunner);
   EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet());
   EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet());
diff --git a/base/timer/timer_unittest.cc b/base/timer/timer_unittest.cc
index 07b8002..a2cc476 100644
--- a/base/timer/timer_unittest.cc
+++ b/base/timer/timer_unittest.cc
@@ -33,11 +33,12 @@
 
 namespace {
 
-// The message loops on which each timer should be tested.
-const MessageLoop::Type testing_message_loops[] = {
-    MessageLoop::TYPE_DEFAULT, MessageLoop::TYPE_IO,
+// The main thread types on which each timer should be tested.
+const test::ScopedTaskEnvironment::MainThreadType testing_main_threads[] = {
+    test::ScopedTaskEnvironment::MainThreadType::DEFAULT,
+    test::ScopedTaskEnvironment::MainThreadType::IO,
 #if !defined(OS_IOS)  // iOS does not allow direct running of the UI loop.
-    MessageLoop::TYPE_UI,
+    test::ScopedTaskEnvironment::MainThreadType::UI,
 #endif
 };
 
@@ -109,7 +110,7 @@
     timer_->SetTaskRunner(std::move(task_runner));
 
     // Run() will be invoked on |task_runner| but |run_loop_|'s QuitClosure
-    // needs to run on this thread (where the MessageLoop lives).
+    // needs to run on this thread (where the task environment lives).
     quit_closure_ = BindOnce(IgnoreResult(&SequencedTaskRunner::PostTask),
                              SequencedTaskRunnerHandle::Get(), FROM_HERE,
                              run_loop_.QuitClosure());
@@ -197,8 +198,9 @@
 // Basic test with same setup as RunTest_OneShotTimers_Cancel below to confirm
 // that |did_run_a| would be signaled in that test if it wasn't for the
 // deletion.
-void RunTest_OneShotTimers(MessageLoop::Type message_loop_type) {
-  MessageLoop loop(message_loop_type);
+void RunTest_OneShotTimers(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type) {
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   WaitableEvent did_run_a(WaitableEvent::ResetPolicy::MANUAL,
                           WaitableEvent::InitialState::NOT_SIGNALED);
@@ -213,8 +215,9 @@
   EXPECT_TRUE(did_run_a.IsSignaled());
 }
 
-void RunTest_OneShotTimers_Cancel(MessageLoop::Type message_loop_type) {
-  MessageLoop loop(message_loop_type);
+void RunTest_OneShotTimers_Cancel(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type) {
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   WaitableEvent did_run_a(WaitableEvent::ResetPolicy::MANUAL,
                           WaitableEvent::InitialState::NOT_SIGNALED);
@@ -234,26 +237,29 @@
   EXPECT_FALSE(did_run_a.IsSignaled());
 }
 
-void RunTest_OneShotSelfDeletingTimer(MessageLoop::Type message_loop_type) {
-  MessageLoop loop(message_loop_type);
+void RunTest_OneShotSelfDeletingTimer(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type) {
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   OneShotSelfDeletingTimerTester f;
   f.Start();
   f.WaitAndConfirmTimerFiredAfterDelay();
 }
 
-void RunTest_RepeatingTimer(MessageLoop::Type message_loop_type,
-                            const TimeDelta& delay) {
-  MessageLoop loop(message_loop_type);
+void RunTest_RepeatingTimer(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type,
+    const TimeDelta& delay) {
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   RepeatingTimerTester f(nullptr, delay);
   f.Start();
   f.WaitAndConfirmTimerFiredRepeatedlyAfterDelay();
 }
 
-void RunTest_RepeatingTimer_Cancel(MessageLoop::Type message_loop_type,
-                                   const TimeDelta& delay) {
-  MessageLoop loop(message_loop_type);
+void RunTest_RepeatingTimer_Cancel(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type,
+    const TimeDelta& delay) {
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   WaitableEvent did_run_a(WaitableEvent::ResetPolicy::MANUAL,
                           WaitableEvent::InitialState::NOT_SIGNALED);
@@ -288,8 +294,9 @@
   bool signaled_ = false;
 };
 
-void RunTest_DelayTimer_NoCall(MessageLoop::Type message_loop_type) {
-  MessageLoop loop(message_loop_type);
+void RunTest_DelayTimer_NoCall(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type) {
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   // If Delay is never called, the timer shouldn't go off.
   DelayTimerTarget target;
@@ -303,8 +310,9 @@
   ASSERT_FALSE(target.signaled());
 }
 
-void RunTest_DelayTimer_OneCall(MessageLoop::Type message_loop_type) {
-  MessageLoop loop(message_loop_type);
+void RunTest_DelayTimer_OneCall(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type) {
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   DelayTimerTarget target;
   DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(1), &target,
@@ -332,8 +340,9 @@
   DelayTimerTarget* const target_;
 };
 
-void RunTest_DelayTimer_Reset(MessageLoop::Type message_loop_type) {
-  MessageLoop loop(message_loop_type);
+void RunTest_DelayTimer_Reset(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type) {
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   // If Delay is never called, the timer shouldn't go off.
   DelayTimerTarget target;
@@ -363,8 +372,9 @@
   }
 };
 
-void RunTest_DelayTimer_Deleted(MessageLoop::Type message_loop_type) {
-  MessageLoop loop(message_loop_type);
+void RunTest_DelayTimer_Deleted(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type) {
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   DelayTimerFatalTarget target;
 
@@ -382,33 +392,31 @@
 }  // namespace
 
 //-----------------------------------------------------------------------------
-// Each test is run against each type of MessageLoop.  That way we are sure
+// Each test is run against each type of main thread.  That way we are sure
 // that timers work properly in all configurations.
 
-TEST(TimerTest, OneShotTimers) {
-  for (auto i : testing_message_loops) {
-    RunTest_OneShotTimers(i);
-  }
+class TimerTestWithThreadType
+    : public testing::TestWithParam<
+          test::ScopedTaskEnvironment::MainThreadType> {};
+
+TEST_P(TimerTestWithThreadType, OneShotTimers) {
+  RunTest_OneShotTimers(GetParam());
 }
 
-TEST(TimerTest, OneShotTimers_Cancel) {
-  for (auto i : testing_message_loops) {
-    RunTest_OneShotTimers_Cancel(i);
-  }
+TEST_P(TimerTestWithThreadType, OneShotTimers_Cancel) {
+  RunTest_OneShotTimers_Cancel(GetParam());
 }
 
 // If underline timer does not handle properly, we will crash or fail
 // in full page heap environment.
-TEST(TimerTest, OneShotSelfDeletingTimer) {
-  for (auto i : testing_message_loops) {
-    RunTest_OneShotSelfDeletingTimer(i);
-  }
+TEST_P(TimerTestWithThreadType, OneShotSelfDeletingTimer) {
+  RunTest_OneShotSelfDeletingTimer(GetParam());
 }
 
 TEST(TimerTest, OneShotTimer_CustomTaskRunner) {
-  // A MessageLoop is required for the timer events on the other thread to
+  // A task environment is required for the timer events on the other thread to
   // communicate back to the Timer under test.
-  MessageLoop loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
 
   Thread other_thread("OneShotTimer_CustomTaskRunner");
   other_thread.Start();
@@ -423,109 +431,89 @@
   f.WaitAndConfirmTimerFiredAfterDelay();
   EXPECT_TRUE(did_run.IsSignaled());
 
-  // |f| should already have communicated back to this |loop| before invoking
-  // Run() and as such this thread should already be aware that |f| is no longer
-  // running.
-  EXPECT_TRUE(loop.IsIdleForTesting());
+  // |f| should already have communicated back to this main thread before
+  // invoking Run() and as such this thread should already be aware that |f| is
+  // no longer running.
+  EXPECT_FALSE(scoped_task_environment.MainThreadHasPendingTask());
   EXPECT_FALSE(f.IsRunning());
 }
 
 TEST(TimerTest, OneShotTimerWithTickClock) {
-  scoped_refptr<TestMockTimeTaskRunner> task_runner(
-      new TestMockTimeTaskRunner(Time::Now(), TimeTicks::Now()));
-  MessageLoop message_loop;
-  message_loop.SetTaskRunner(task_runner);
+  test::ScopedTaskEnvironment scoped_task_environment(
+      test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
   Receiver receiver;
-  OneShotTimer timer(task_runner->GetMockTickClock());
+  OneShotTimer timer(scoped_task_environment.GetMockTickClock());
   timer.Start(FROM_HERE, TimeDelta::FromSeconds(1),
               BindOnce(&Receiver::OnCalled, Unretained(&receiver)));
-  task_runner->FastForwardBy(TimeDelta::FromSeconds(1));
+  scoped_task_environment.FastForwardBy(TimeDelta::FromSeconds(1));
   EXPECT_TRUE(receiver.WasCalled());
 }
 
-TEST(TimerTest, RepeatingTimer) {
-  for (auto i : testing_message_loops) {
-    RunTest_RepeatingTimer(i, TimeDelta::FromMilliseconds(10));
-  }
+TEST_P(TimerTestWithThreadType, RepeatingTimer) {
+  RunTest_RepeatingTimer(GetParam(), TimeDelta::FromMilliseconds(10));
 }
 
-TEST(TimerTest, RepeatingTimer_Cancel) {
-  for (auto i : testing_message_loops) {
-    RunTest_RepeatingTimer_Cancel(i, TimeDelta::FromMilliseconds(10));
-  }
+TEST_P(TimerTestWithThreadType, RepeatingTimer_Cancel) {
+  RunTest_RepeatingTimer_Cancel(GetParam(), TimeDelta::FromMilliseconds(10));
 }
 
-TEST(TimerTest, RepeatingTimerZeroDelay) {
-  for (auto i : testing_message_loops) {
-    RunTest_RepeatingTimer(i, TimeDelta::FromMilliseconds(0));
-  }
+TEST_P(TimerTestWithThreadType, RepeatingTimerZeroDelay) {
+  RunTest_RepeatingTimer(GetParam(), TimeDelta::FromMilliseconds(0));
 }
 
-TEST(TimerTest, RepeatingTimerZeroDelay_Cancel) {
-  for (auto i : testing_message_loops) {
-    RunTest_RepeatingTimer_Cancel(i, TimeDelta::FromMilliseconds(0));
-  }
+TEST_P(TimerTestWithThreadType, RepeatingTimerZeroDelay_Cancel) {
+  RunTest_RepeatingTimer_Cancel(GetParam(), TimeDelta::FromMilliseconds(0));
 }
 
 TEST(TimerTest, RepeatingTimerWithTickClock) {
-  scoped_refptr<TestMockTimeTaskRunner> task_runner(
-      new TestMockTimeTaskRunner(Time::Now(), TimeTicks::Now()));
-  MessageLoop message_loop;
-  message_loop.SetTaskRunner(task_runner);
+  test::ScopedTaskEnvironment scoped_task_environment(
+      test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
   Receiver receiver;
   const int expected_times_called = 10;
-  RepeatingTimer timer(task_runner->GetMockTickClock());
+  RepeatingTimer timer(scoped_task_environment.GetMockTickClock());
   timer.Start(FROM_HERE, TimeDelta::FromSeconds(1),
               BindRepeating(&Receiver::OnCalled, Unretained(&receiver)));
-  task_runner->FastForwardBy(TimeDelta::FromSeconds(expected_times_called));
+  scoped_task_environment.FastForwardBy(
+      TimeDelta::FromSeconds(expected_times_called));
   timer.Stop();
   EXPECT_EQ(expected_times_called, receiver.TimesCalled());
 }
 
-TEST(TimerTest, DelayTimer_NoCall) {
-  for (auto i : testing_message_loops) {
-    RunTest_DelayTimer_NoCall(i);
-  }
+TEST_P(TimerTestWithThreadType, DelayTimer_NoCall) {
+  RunTest_DelayTimer_NoCall(GetParam());
 }
 
-TEST(TimerTest, DelayTimer_OneCall) {
-  for (auto i : testing_message_loops) {
-    RunTest_DelayTimer_OneCall(i);
-  }
+TEST_P(TimerTestWithThreadType, DelayTimer_OneCall) {
+  RunTest_DelayTimer_OneCall(GetParam());
 }
 
 // It's flaky on the buildbot, http://crbug.com/25038.
-TEST(TimerTest, DISABLED_DelayTimer_Reset) {
-  for (auto i : testing_message_loops) {
-    RunTest_DelayTimer_Reset(i);
-  }
+TEST_P(TimerTestWithThreadType, DISABLED_DelayTimer_Reset) {
+  RunTest_DelayTimer_Reset(GetParam());
 }
 
-TEST(TimerTest, DelayTimer_Deleted) {
-  for (auto i : testing_message_loops) {
-    RunTest_DelayTimer_Deleted(i);
-  }
+TEST_P(TimerTestWithThreadType, DelayTimer_Deleted) {
+  RunTest_DelayTimer_Deleted(GetParam());
 }
 
 TEST(TimerTest, DelayTimerWithTickClock) {
-  scoped_refptr<TestMockTimeTaskRunner> task_runner(
-      new TestMockTimeTaskRunner(Time::Now(), TimeTicks::Now()));
-  MessageLoop message_loop;
-  message_loop.SetTaskRunner(task_runner);
+  test::ScopedTaskEnvironment scoped_task_environment(
+      test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME);
   Receiver receiver;
   DelayTimer timer(FROM_HERE, TimeDelta::FromSeconds(1), &receiver,
-                   &Receiver::OnCalled, task_runner->GetMockTickClock());
-  task_runner->FastForwardBy(TimeDelta::FromMilliseconds(999));
+                   &Receiver::OnCalled,
+                   scoped_task_environment.GetMockTickClock());
+  scoped_task_environment.FastForwardBy(TimeDelta::FromMilliseconds(999));
   EXPECT_FALSE(receiver.WasCalled());
   timer.Reset();
-  task_runner->FastForwardBy(TimeDelta::FromMilliseconds(999));
+  scoped_task_environment.FastForwardBy(TimeDelta::FromMilliseconds(999));
   EXPECT_FALSE(receiver.WasCalled());
   timer.Reset();
-  task_runner->FastForwardBy(TimeDelta::FromSeconds(1));
+  scoped_task_environment.FastForwardBy(TimeDelta::FromSeconds(1));
   EXPECT_TRUE(receiver.WasCalled());
 }
 
-TEST(TimerTest, MessageLoopShutdown) {
+TEST(TimerTest, TaskEnvironmentShutdown) {
   // This test is designed to verify that shutdown of the
   // message loop does not cause crashes if there were pending
   // timers not yet fired.  It may only trigger exceptions
@@ -538,10 +526,10 @@
     OneShotTimerTesterBase c(&did_run);
     OneShotTimerTesterBase d(&did_run);
     {
-      MessageLoop loop;
+      test::ScopedTaskEnvironment scoped_task_environment;
       a.Start();
       b.Start();
-    }  // MessageLoop destructs by falling out of scope.
+    }  // Task environment destructs by falling out of scope.
   }  // OneShotTimers destruct.  SHOULD NOT CRASH, of course.
 
   EXPECT_FALSE(did_run.IsSignaled());
@@ -575,20 +563,20 @@
   DISALLOW_COPY_AND_ASSIGN(OneShotSelfOwningTimerTester);
 };
 
-TEST(TimerTest, MessageLoopShutdownSelfOwningTimer) {
-  // This test verifies that shutdown of the message loop does not cause crashes
-  // if there is a pending timer not yet fired and |Timer::user_task_| owns the
-  // timer. The test may only trigger exceptions if debug heap checking is
-  // enabled.
+TEST(TimerTest, TaskEnvironmentShutdownSelfOwningTimer) {
+  // This test verifies that shutdown of the task environment does not cause
+  // crashes if there is a pending timer not yet fired and |Timer::user_task_|
+  // owns the timer. The test may only trigger exceptions if debug heap checking
+  // is enabled.
 
-  MessageLoop loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
   scoped_refptr<OneShotSelfOwningTimerTester> tester =
       new OneShotSelfOwningTimerTester();
 
   std::move(tester)->StartTimer();
   // |Timer::user_task_| owns sole reference to |tester|.
 
-  // MessageLoop destructs by falling out of scope. SHOULD NOT CRASH.
+  // Task environment destructs by falling out of scope. SHOULD NOT CRASH.
 }
 
 void TimerTestCallback() {
@@ -596,7 +584,7 @@
 
 TEST(TimerTest, NonRepeatIsRunning) {
   {
-    MessageLoop loop;
+    test::ScopedTaskEnvironment scoped_task_environment;
     OneShotTimer timer;
     EXPECT_FALSE(timer.IsRunning());
     timer.Start(FROM_HERE, TimeDelta::FromDays(1),
@@ -608,7 +596,7 @@
 
   {
     RetainingOneShotTimer timer;
-    MessageLoop loop;
+    test::ScopedTaskEnvironment scoped_task_environment;
     EXPECT_FALSE(timer.IsRunning());
     timer.Start(FROM_HERE, TimeDelta::FromDays(1),
                 BindRepeating(&TimerTestCallback));
@@ -621,10 +609,10 @@
   }
 }
 
-TEST(TimerTest, NonRepeatMessageLoopDeath) {
+TEST(TimerTest, NonRepeatTaskEnvironmentDeath) {
   OneShotTimer timer;
   {
-    MessageLoop loop;
+    test::ScopedTaskEnvironment scoped_task_environment;
     EXPECT_FALSE(timer.IsRunning());
     timer.Start(FROM_HERE, TimeDelta::FromDays(1),
                 BindOnce(&TimerTestCallback));
@@ -634,7 +622,7 @@
 }
 
 TEST(TimerTest, RetainRepeatIsRunning) {
-  MessageLoop loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
   RepeatingTimer timer(FROM_HERE, TimeDelta::FromDays(1),
                        BindRepeating(&TimerTestCallback));
   EXPECT_FALSE(timer.IsRunning());
@@ -647,7 +635,7 @@
 }
 
 TEST(TimerTest, RetainNonRepeatIsRunning) {
-  MessageLoop loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
   RetainingOneShotTimer timer(FROM_HERE, TimeDelta::FromDays(1),
                               BindRepeating(&TimerTestCallback));
   EXPECT_FALSE(timer.IsRunning());
@@ -686,7 +674,7 @@
 TEST(TimerTest, ContinuationStopStart) {
   {
     ClearAllCallbackHappened();
-    MessageLoop loop;
+    test::ScopedTaskEnvironment scoped_task_environment;
     OneShotTimer timer;
     timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10),
                 BindOnce(&SetCallbackHappened1));
@@ -702,7 +690,7 @@
 TEST(TimerTest, ContinuationReset) {
   {
     ClearAllCallbackHappened();
-    MessageLoop loop;
+    test::ScopedTaskEnvironment scoped_task_environment;
     OneShotTimer timer;
     timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10),
                 BindOnce(&SetCallbackHappened1));
@@ -714,6 +702,10 @@
   }
 }
 
+INSTANTIATE_TEST_CASE_P(,
+                        TimerTestWithThreadType,
+                        testing::ValuesIn(testing_main_threads));
+
 namespace {
 
 // Fixture for tests requiring ScopedTaskEnvironment. Includes a WaitableEvent
@@ -771,7 +763,7 @@
     Signal();
   }
 
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  test::ScopedTaskEnvironment scoped_task_environment_;
   WaitableEvent event_;
   std::unique_ptr<OneShotTimer> timer_;
 
@@ -798,7 +790,7 @@
 
   // Spin the loop so that the delayed task fires on it, which will forward it
   // to |task_runner|. And since the Timer's task is one that posts back to this
-  // MessageLoop to quit, we finally unblock.
+  // thread to quit, we finally unblock.
   run_loop_.Run();
 
   // Timer will be destroyed on this thread.
diff --git a/base/trace_event/blame_context_unittest.cc b/base/trace_event/blame_context_unittest.cc
index f628115..ad7bad5 100644
--- a/base/trace_event/blame_context_unittest.cc
+++ b/base/trace_event/blame_context_unittest.cc
@@ -5,7 +5,7 @@
 #include "base/trace_event/blame_context.h"
 
 #include "base/json/json_writer.h"
-#include "base/message_loop/message_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/test/trace_event_analyzer.h"
 #include "base/trace_event/traced_value.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -58,7 +58,7 @@
 
 class BlameContextTest : public testing::Test {
  protected:
-  MessageLoop loop_;
+  test::ScopedTaskEnvironment scoped_task_environment_;
 };
 
 TEST_F(BlameContextTest, EnterAndLeave) {
diff --git a/base/trace_event/trace_event_system_stats_monitor_unittest.cc b/base/trace_event/trace_event_system_stats_monitor_unittest.cc
index 52a05ba9..8688d71 100644
--- a/base/trace_event/trace_event_system_stats_monitor_unittest.cc
+++ b/base/trace_event/trace_event_system_stats_monitor_unittest.cc
@@ -8,8 +8,9 @@
 #include <string>
 
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event_impl.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -32,14 +33,14 @@
 //////////////////////////////////////////////////////////////////////////////
 
 TEST_F(TraceSystemStatsMonitorTest, TraceEventSystemStatsMonitor) {
-  MessageLoop message_loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
 
   // Start with no observers of the TraceLog.
   EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
 
   // Creating a system stats monitor adds it to the TraceLog observer list.
   std::unique_ptr<TraceEventSystemStatsMonitor> system_stats_monitor(
-      new TraceEventSystemStatsMonitor(message_loop.task_runner()));
+      new TraceEventSystemStatsMonitor(ThreadTaskRunnerHandle::Get()));
   EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
   EXPECT_TRUE(
       TraceLog::GetInstance()->HasEnabledStateObserver(
diff --git a/base/win/object_watcher_unittest.cc b/base/win/object_watcher_unittest.cc
index 5aa3891..bbec192 100644
--- a/base/win/object_watcher_unittest.cc
+++ b/base/win/object_watcher_unittest.cc
@@ -5,9 +5,10 @@
 #include "base/win/object_watcher.h"
 
 #include <process.h>
+#include <windows.h>
 
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -32,8 +33,9 @@
   int* counter_;
 };
 
-void RunTest_BasicSignal(MessageLoop::Type message_loop_type) {
-  MessageLoop message_loop(message_loop_type);
+void RunTest_BasicSignal(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type) {
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   ObjectWatcher watcher;
   EXPECT_FALSE(watcher.IsWatching());
@@ -55,8 +57,9 @@
   CloseHandle(event);
 }
 
-void RunTest_BasicCancel(MessageLoop::Type message_loop_type) {
-  MessageLoop message_loop(message_loop_type);
+void RunTest_BasicCancel(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type) {
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   ObjectWatcher watcher;
 
@@ -72,8 +75,9 @@
   CloseHandle(event);
 }
 
-void RunTest_CancelAfterSet(MessageLoop::Type message_loop_type) {
-  MessageLoop message_loop(message_loop_type);
+void RunTest_CancelAfterSet(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type) {
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   ObjectWatcher watcher;
 
@@ -101,8 +105,9 @@
   CloseHandle(event);
 }
 
-void RunTest_SignalBeforeWatch(MessageLoop::Type message_loop_type) {
-  MessageLoop message_loop(message_loop_type);
+void RunTest_SignalBeforeWatch(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type) {
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   ObjectWatcher watcher;
 
@@ -119,15 +124,16 @@
   CloseHandle(event);
 }
 
-void RunTest_OutlivesMessageLoop(MessageLoop::Type message_loop_type) {
-  // Simulate a MessageLoop that dies before an ObjectWatcher.  This ordinarily
-  // doesn't happen when people use the Thread class, but it can happen when
-  // people use the Singleton pattern or atexit.
+void RunTest_OutlivesTaskEnvironment(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type) {
+  // Simulate a task environment that dies before an ObjectWatcher.  This
+  // ordinarily doesn't happen when people use the Thread class, but it can
+  // happen when people use the Singleton pattern or atexit.
   HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);  // not signaled
   {
     ObjectWatcher watcher;
     {
-      MessageLoop message_loop(message_loop_type);
+      test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
       QuitDelegate delegate;
       watcher.StartWatchingOnce(event, &delegate);
@@ -153,8 +159,9 @@
   int iterations_;
 };
 
-void RunTest_ExecuteMultipleTimes(MessageLoop::Type message_loop_type) {
-  MessageLoop message_loop(message_loop_type);
+void RunTest_ExecuteMultipleTimes(
+    test::ScopedTaskEnvironment::MainThreadType main_thread_type) {
+  test::ScopedTaskEnvironment scoped_task_environment(main_thread_type);
 
   ObjectWatcher watcher;
   EXPECT_FALSE(watcher.IsWatching());
@@ -182,39 +189,44 @@
 //-----------------------------------------------------------------------------
 
 TEST(ObjectWatcherTest, BasicSignal) {
-  RunTest_BasicSignal(MessageLoop::TYPE_DEFAULT);
-  RunTest_BasicSignal(MessageLoop::TYPE_IO);
-  RunTest_BasicSignal(MessageLoop::TYPE_UI);
+  RunTest_BasicSignal(test::ScopedTaskEnvironment::MainThreadType::DEFAULT);
+  RunTest_BasicSignal(test::ScopedTaskEnvironment::MainThreadType::IO);
+  RunTest_BasicSignal(test::ScopedTaskEnvironment::MainThreadType::UI);
 }
 
 TEST(ObjectWatcherTest, BasicCancel) {
-  RunTest_BasicCancel(MessageLoop::TYPE_DEFAULT);
-  RunTest_BasicCancel(MessageLoop::TYPE_IO);
-  RunTest_BasicCancel(MessageLoop::TYPE_UI);
+  RunTest_BasicCancel(test::ScopedTaskEnvironment::MainThreadType::DEFAULT);
+  RunTest_BasicCancel(test::ScopedTaskEnvironment::MainThreadType::IO);
+  RunTest_BasicCancel(test::ScopedTaskEnvironment::MainThreadType::UI);
 }
 
 TEST(ObjectWatcherTest, CancelAfterSet) {
-  RunTest_CancelAfterSet(MessageLoop::TYPE_DEFAULT);
-  RunTest_CancelAfterSet(MessageLoop::TYPE_IO);
-  RunTest_CancelAfterSet(MessageLoop::TYPE_UI);
+  RunTest_CancelAfterSet(test::ScopedTaskEnvironment::MainThreadType::DEFAULT);
+  RunTest_CancelAfterSet(test::ScopedTaskEnvironment::MainThreadType::IO);
+  RunTest_CancelAfterSet(test::ScopedTaskEnvironment::MainThreadType::UI);
 }
 
 TEST(ObjectWatcherTest, SignalBeforeWatch) {
-  RunTest_SignalBeforeWatch(MessageLoop::TYPE_DEFAULT);
-  RunTest_SignalBeforeWatch(MessageLoop::TYPE_IO);
-  RunTest_SignalBeforeWatch(MessageLoop::TYPE_UI);
+  RunTest_SignalBeforeWatch(
+      test::ScopedTaskEnvironment::MainThreadType::DEFAULT);
+  RunTest_SignalBeforeWatch(test::ScopedTaskEnvironment::MainThreadType::IO);
+  RunTest_SignalBeforeWatch(test::ScopedTaskEnvironment::MainThreadType::UI);
 }
 
-TEST(ObjectWatcherTest, OutlivesMessageLoop) {
-  RunTest_OutlivesMessageLoop(MessageLoop::TYPE_DEFAULT);
-  RunTest_OutlivesMessageLoop(MessageLoop::TYPE_IO);
-  RunTest_OutlivesMessageLoop(MessageLoop::TYPE_UI);
+TEST(ObjectWatcherTest, OutlivesTaskEnvironment) {
+  RunTest_OutlivesTaskEnvironment(
+      test::ScopedTaskEnvironment::MainThreadType::DEFAULT);
+  RunTest_OutlivesTaskEnvironment(
+      test::ScopedTaskEnvironment::MainThreadType::IO);
+  RunTest_OutlivesTaskEnvironment(
+      test::ScopedTaskEnvironment::MainThreadType::UI);
 }
 
 TEST(ObjectWatcherTest, ExecuteMultipleTimes) {
-  RunTest_ExecuteMultipleTimes(MessageLoop::TYPE_DEFAULT);
-  RunTest_ExecuteMultipleTimes(MessageLoop::TYPE_IO);
-  RunTest_ExecuteMultipleTimes(MessageLoop::TYPE_UI);
+  RunTest_ExecuteMultipleTimes(
+      test::ScopedTaskEnvironment::MainThreadType::DEFAULT);
+  RunTest_ExecuteMultipleTimes(test::ScopedTaskEnvironment::MainThreadType::IO);
+  RunTest_ExecuteMultipleTimes(test::ScopedTaskEnvironment::MainThreadType::UI);
 }
 
 }  // namespace win
diff --git a/base/win/registry_unittest.cc b/base/win/registry_unittest.cc
index 5a18ffa..ee960cf9 100644
--- a/base/win/registry_unittest.cc
+++ b/base/win/registry_unittest.cc
@@ -5,6 +5,7 @@
 #include "base/win/registry.h"
 
 #include <stdint.h>
+#include <windows.h>
 
 #include <cstring>
 #include <vector>
@@ -12,9 +13,9 @@
 #include "base/bind.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/win/windows_version.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -378,7 +379,7 @@
 TEST_F(RegistryTest, ChangeCallback) {
   RegKey key;
   TestChangeDelegate delegate;
-  MessageLoop message_loop;
+  test::ScopedTaskEnvironment scoped_task_environment;
 
   std::wstring foo_key(kRootKey);
   foo_key += L"\\Foo";
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index f87d81f..7826eed 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -743,6 +743,7 @@
     "//chrome/test/data/translate/",
     "//chrome/test/media_router/resources/",
     "//components/test/data/payments/",
+    "//content/test/data/browsing_data/",
     "//content/test/data/android/authenticator.html",
     "//content/test/data/android/geolocation.html",
     "//content/test/data/android/installedapp.html",
diff --git a/chrome/android/java/res/drawable/ic_keyboard.xml b/chrome/android/java/res/drawable/ic_keyboard.xml
new file mode 100644
index 0000000..b626cbf
--- /dev/null
+++ b/chrome/android/java/res/drawable/ic_keyboard.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools"
+        tools:targetApi="21"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="@color/default_icon_color"
+        android:pathData="M 21.55 3.12 L 2.464 3.12 C 1.145 3.12 0.087 4.19 0.087 5.505 L 0.075 17.436 C 0.075 18.755 1.145 19.821 2.464 19.821 L 21.55 19.821 C 22.869 19.821 23.939 18.755 23.939 17.436 L 23.939 5.505 C 23.939 4.19 22.869 3.12 21.55 3.12 Z M 10.814 6.701 L 13.199 6.701 L 13.199 9.086 L 10.814 9.086 L 10.814 6.701 Z M 10.814 10.278 L 13.199 10.278 L 13.199 12.663 L 10.814 12.663 L 10.814 10.278 Z M 7.233 6.701 L 9.622 6.701 L 9.622 9.086 L 7.233 9.086 L 7.233 6.701 Z M 7.233 10.278 L 9.622 10.278 L 9.622 12.663 L 7.233 12.663 L 7.233 10.278 Z M 6.041 12.663 L 3.657 12.663 L 3.657 10.278 L 6.041 10.278 L 6.041 12.663 Z M 6.041 9.086 L 3.657 9.086 L 3.657 6.701 L 6.041 6.701 L 6.041 9.086 Z M 16.78 17.436 L 7.233 17.436 L 7.233 15.052 L 16.78 15.052 L 16.78 17.436 Z M 16.78 12.663 L 14.392 12.663 L 14.392 10.278 L 16.78 10.278 L 16.78 12.663 Z M 16.78 9.086 L 14.392 9.086 L 14.392 6.701 L 16.78 6.701 L 16.78 9.086 Z M 20.357 12.663 L 17.973 12.663 L 17.973 10.278 L 20.357 10.278 L 20.357 12.663 Z M 20.357 9.086 L 17.973 9.086 L 17.973 6.701 L 20.357 6.701 L 20.357 9.086 Z M 12.007 26.983"/>
+</vector>
diff --git a/chrome/android/java/res/layout/keyboard_accessory_modern.xml b/chrome/android/java/res/layout/keyboard_accessory_modern.xml
new file mode 100644
index 0000000..9d2cb522
--- /dev/null
+++ b/chrome/android/java/res/layout/keyboard_accessory_modern.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryModernView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/keyboard_accessory"
+    android:layout_gravity="start|bottom"
+    android:contentDescription="@string/autofill_keyboard_accessory_content_description"
+    android:scrollbars="none"
+    android:visibility="gone"
+    android:orientation="vertical"
+    android:layout_height="@dimen/keyboard_accessory_height_with_shadow"
+    android:layout_width="match_parent"
+    android:paddingEnd="0dp"
+    android:clickable="true"
+    android:focusable="true">
+
+    <ImageView
+        android:id="@+id/accessory_shadow"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/keyboard_accessory_shadow"
+        android:src="@drawable/modern_toolbar_shadow"
+        android:scaleType="fitXY"
+        android:scaleY="-1"
+        tools:ignore="ContentDescription" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:minHeight="@dimen/keyboard_accessory_action_height"
+        android:layout_height="wrap_content"
+        android:layout_gravity="start|bottom"
+        android:orientation="horizontal"
+        android:background="@color/modern_primary_color">
+
+        <ImageView
+            android:id="@+id/show_keyboard"
+            android:layout_width="wrap_content"
+            android:layout_weight="0"
+            android:layout_height="match_parent"
+            android:paddingStart="@dimen/keyboard_accessory_action_padding"
+            android:paddingEnd="@dimen/keyboard_accessory_action_padding"
+            android:paddingTop="@dimen/keyboard_accessory_padding"
+            android:paddingBottom="@dimen/keyboard_accessory_padding"
+            android:clickable="true"
+            android:focusable="true"
+            android:contentDescription="@string/keyboard_accessory_sheet_hide"
+            android:background="?attr/selectableItemBackground"/>
+
+        <android.support.v7.widget.RecyclerView
+            android:id="@+id/actions_view"
+            android:layout_weight="1"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+
+        <View
+            android:id="@+id/tabs_actions_spacer"
+            android:layout_weight="1"
+            android:layout_height="match_parent"
+            android:layout_width="match_parent"
+            android:background="@null" />
+
+        <View
+            android:id="@+id/tabs_actions_divider"
+            android:layout_weight="0"
+            style="@style/VerticalDivider" />
+
+        <android.support.design.widget.TabLayout
+            android:id="@+id/tabs"
+            app:tabIndicatorHeight="0dp"
+            android:layout_gravity="end"
+            android:layout_width="wrap_content"
+            android:layout_weight="0"
+            android:layout_height="match_parent"/>
+    </LinearLayout>
+
+</org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryModernView>
diff --git a/chrome/android/java/res/layout/keyboard_accessory_suggestion.xml b/chrome/android/java/res/layout/keyboard_accessory_suggestion.xml
new file mode 100644
index 0000000..901ced2
--- /dev/null
+++ b/chrome/android/java/res/layout/keyboard_accessory_suggestion.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:gravity="center"
+    android:minHeight="@dimen/keyboard_accessory_action_height"
+    android:layout_height="wrap_content"
+    android:layout_width="wrap_content"
+    android:paddingBottom="0dp"
+    android:paddingEnd="@dimen/keyboard_accessory_half_padding"
+    android:paddingStart="@dimen/keyboard_accessory_half_padding"
+    android:paddingTop="0dp"
+    android:layout_marginBottom="@dimen/keyboard_accessory_half_padding"
+    android:layout_marginTop="@dimen/keyboard_accessory_half_padding"
+    android:textAppearance="@style/BlackTitle2"/>
diff --git a/chrome/android/java/res/layout/keyboard_accessory_tabs.xml b/chrome/android/java/res/layout/keyboard_accessory_tabs.xml
new file mode 100644
index 0000000..b88a339
--- /dev/null
+++ b/chrome/android/java/res/layout/keyboard_accessory_tabs.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<android.support.design.widget.TabLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/tabs"
+    app:tabIndicatorHeight="0dp"
+    android:layout_gravity="end"
+    android:layout_width="wrap_content"
+    android:layout_weight="0"
+    android:layout_height="match_parent"/>
\ No newline at end of file
diff --git a/chrome/android/java/res_autofill_assistant/layout/autofill_assistant_payment_request.xml b/chrome/android/java/res_autofill_assistant/layout/autofill_assistant_payment_request.xml
index 95452f09..849238ac 100644
--- a/chrome/android/java/res_autofill_assistant/layout/autofill_assistant_payment_request.xml
+++ b/chrome/android/java/res_autofill_assistant/layout/autofill_assistant_payment_request.xml
@@ -30,6 +30,8 @@
             android:id="@+id/payment_container_layout"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:paddingStart="8dp"
+            android:paddingEnd="8dp"
             android:orientation="vertical" />
 
     </org.chromium.chrome.browser.widget.FadingEdgeScrollView>
@@ -39,13 +41,21 @@
     checkbox field, so we wrap it in a FrameLayout and control the margins and
     padding there.
     -->
+    <TextView
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:layout_marginStart="@dimen/editor_dialog_section_large_spacing"
+        android:layout_marginTop="@dimen/editor_dialog_section_small_spacing"
+        android:textAppearance="@style/BlueLink2"
+        android:text="@string/autofill_assistant_terms_title" />
+
     <FrameLayout
         android:layout_height="wrap_content"
         android:layout_width="match_parent"
-        android:layout_marginStart="16dp"
-        android:layout_marginEnd="16dp"
-        android:layout_marginTop="28dp"
-        android:layout_marginBottom="20dp"
+        android:layout_marginStart="@dimen/editor_dialog_section_large_spacing"
+        android:layout_marginEnd="@dimen/editor_dialog_section_large_spacing"
+        android:layout_marginTop="@dimen/editor_dialog_section_small_spacing"
+        android:layout_marginBottom="@dimen/editor_dialog_section_small_spacing"
         android:paddingTop="9dp"
         android:paddingBottom="9dp"
         android:paddingStart="12dp"
diff --git a/chrome/android/java/res_autofill_assistant/layout/autofill_assistant_payment_request_bottom_bar.xml b/chrome/android/java/res_autofill_assistant/layout/autofill_assistant_payment_request_bottom_bar.xml
index 4073213..3baeaa4 100644
--- a/chrome/android/java/res_autofill_assistant/layout/autofill_assistant_payment_request_bottom_bar.xml
+++ b/chrome/android/java/res_autofill_assistant/layout/autofill_assistant_payment_request_bottom_bar.xml
@@ -20,6 +20,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:minHeight="36dp"
+        android:layout_marginEnd="0dp"
         android:text="@string/next"
         style="@style/FilledButton.Flat" />
 </org.chromium.chrome.browser.autofill_assistant.ui.PaymentRequestBottomBar>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 7bd3950..b3dcf47 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -163,7 +163,6 @@
 import org.chromium.printing.PrintManagerDelegateImpl;
 import org.chromium.printing.PrintingController;
 import org.chromium.printing.PrintingControllerImpl;
-import org.chromium.ui.DeferredViewStubInflationProvider;
 import org.chromium.ui.UiUtils;
 import org.chromium.ui.base.ActivityWindowAndroid;
 import org.chromium.ui.base.DeviceFormFactor;
@@ -703,7 +702,7 @@
             }
 
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 postDeferredStartupIfNeeded();
                 OfflinePageUtils.showOfflineSnackbarIfNecessary(tab);
             }
@@ -1434,16 +1433,11 @@
         }
         super.finishNativeInitialization();
 
-        ViewGroup coordinator = findViewById(R.id.coordinator);
-        ViewStub accessoryBarStub = findViewById(R.id.keyboard_accessory_stub);
-        ViewStub accessorySheetStub = findViewById(R.id.keyboard_accessory_sheet_stub);
-        if (accessoryBarStub != null && accessorySheetStub != null) {
-            mManualFillingController.initialize(getWindowAndroid(),
-                    new DeferredViewStubInflationProvider<>(accessoryBarStub),
-                    new DeferredViewStubInflationProvider<>(accessorySheetStub));
-            getCompositorViewHolder().setKeyboardExtensionView(
-                    mManualFillingController.getKeyboardExtensionSizeManager());
-        }
+        mManualFillingController.initialize(getWindowAndroid(),
+                findViewById(R.id.keyboard_accessory_stub),
+                findViewById(R.id.keyboard_accessory_sheet_stub));
+        getCompositorViewHolder().setKeyboardExtensionView(
+                mManualFillingController.getKeyboardExtensionSizeManager());
 
         // Create after native initialization so subclasses that override this method have a chance
         // to setup.
@@ -1451,6 +1445,7 @@
 
         if (supportsContextualSuggestionsBottomSheet()
                 && FeatureUtilities.areContextualSuggestionsEnabled(this)) {
+            ViewGroup coordinator = findViewById(R.id.coordinator);
             getLayoutInflater().inflate(R.layout.bottom_sheet, coordinator);
             mBottomSheet = coordinator.findViewById(R.id.bottom_sheet);
             mBottomSheet.init(coordinator, this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index aa9e3a9..4e0abcc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1487,7 +1487,7 @@
 
         mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(mTabModelSelectorImpl) {
             @Override
-            public void onPageLoadFinished(final Tab tab) {
+            public void onPageLoadFinished(final Tab tab, String url) {
                 mAppIndexingUtil.extractCopylessPasteMetadata(tab);
             }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/UrlConstants.java b/chrome/android/java/src/org/chromium/chrome/browser/UrlConstants.java
index e9b3243..9986c8f8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/UrlConstants.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/UrlConstants.java
@@ -36,9 +36,13 @@
     public static final String HTTP_URL_PREFIX = "http://";
     public static final String HTTPS_URL_PREFIX = "https://";
 
+    public static final String ABOUT_URL = "chrome://about/";
+
+    public static final String CHROME_BLANK_URL = "chrome://blank/";
+
     public static final String NTP_HOST = "newtab";
     public static final String NTP_URL = "chrome-native://newtab/";
-    public static final String NTP_NON_NATIVE_URL = "chrome://newtab";
+    public static final String NTP_NON_NATIVE_URL = "chrome://newtab/";
 
     public static final String BOOKMARKS_HOST = "bookmarks";
     public static final String BOOKMARKS_URL = "chrome-native://bookmarks/";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java
index e54f3c5d..d8bf7c4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java
@@ -7,6 +7,7 @@
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.ACTIONS;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.ACTIVE_TAB;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.BOTTOM_OFFSET_PX;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.TABS;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.TAB_SELECTION_CALLBACKS;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.VISIBLE;
@@ -14,12 +15,16 @@
 import android.support.annotation.Px;
 
 import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryModernViewBinder.ModernActionViewHolder;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryViewBinder.ActionViewHolder;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryViewBinder.TabViewBinder;
 import org.chromium.chrome.browser.modelutil.LazyConstructionPropertyMcp;
 import org.chromium.chrome.browser.modelutil.ListModel;
 import org.chromium.chrome.browser.modelutil.ListModelChangeProcessor;
+import org.chromium.chrome.browser.modelutil.PropertyKey;
 import org.chromium.chrome.browser.modelutil.PropertyModel;
+import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor;
 import org.chromium.chrome.browser.modelutil.RecyclerViewAdapter;
 import org.chromium.chrome.browser.modelutil.SimpleRecyclerViewMcp;
 import org.chromium.ui.ViewProvider;
@@ -70,7 +75,7 @@
             ViewProvider<KeyboardAccessoryView> viewProvider) {
         PropertyModel model = new PropertyModel
                                       .Builder(ACTIONS, TABS, VISIBLE, BOTTOM_OFFSET_PX, ACTIVE_TAB,
-                                              TAB_SELECTION_CALLBACKS)
+                                              TAB_SELECTION_CALLBACKS, SHOW_KEYBOARD_CALLBACK)
                                       .with(TABS, new ListModel<>())
                                       .with(ACTIONS, new ListModel<>())
                                       .with(ACTIVE_TAB, null)
@@ -79,8 +84,13 @@
         mMediator = new KeyboardAccessoryMediator(model, visibilityDelegate);
         viewProvider.whenLoaded(view -> view.setTabSelectionAdapter(mMediator));
 
-        LazyConstructionPropertyMcp.create(
-                model, VISIBLE, viewProvider, KeyboardAccessoryViewBinder::bind);
+        PropertyModelChangeProcessor
+                .ViewBinder<PropertyModel, KeyboardAccessoryView, PropertyKey> viewBinder =
+                KeyboardAccessoryViewBinder::bind;
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY)) {
+            viewBinder = KeyboardAccessoryModernViewBinder::bind;
+        }
+        LazyConstructionPropertyMcp.create(model, VISIBLE, viewProvider, viewBinder);
         KeyboardAccessoryMetricsRecorder.registerKeyboardAccessoryModelMetricsObserver(model);
     }
 
@@ -92,10 +102,14 @@
      */
     static RecyclerViewAdapter<ActionViewHolder, Void> createActionsAdapter(
             ListModel<KeyboardAccessoryData.Action> actions) {
+        RecyclerViewAdapter.ViewHolderFactory<ActionViewHolder> factory = ActionViewHolder::create;
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY)) {
+            factory = ModernActionViewHolder::create;
+        }
         return new RecyclerViewAdapter<>(
                 new SimpleRecyclerViewMcp<>(actions, KeyboardAccessoryData.Action::getActionType,
                         ActionViewHolder::bind),
-                ActionViewHolder::create);
+                factory);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java
index 1ab6a78..9c3991d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java
@@ -8,6 +8,7 @@
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.ACTIONS;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.ACTIVE_TAB;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.BOTTOM_OFFSET_PX;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.TABS;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.TAB_SELECTION_CALLBACKS;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.VISIBLE;
@@ -54,6 +55,7 @@
         mModel.get(TABS).addObserver(this);
         mModel.get(ACTIONS).addObserver(this);
         mModel.set(TAB_SELECTION_CALLBACKS, this);
+        mModel.set(SHOW_KEYBOARD_CALLBACK, this::closeSheet);
     }
 
     @Override
@@ -152,7 +154,8 @@
             mVisibilityDelegate.onChangeAccessorySheet(activeTab);
             return;
         }
-        if (propertyKey == BOTTOM_OFFSET_PX || propertyKey == TAB_SELECTION_CALLBACKS) {
+        if (propertyKey == BOTTOM_OFFSET_PX || propertyKey == TAB_SELECTION_CALLBACKS
+                || propertyKey == SHOW_KEYBOARD_CALLBACK) {
             return;
         }
         assert false : "Every property update needs to be handled explicitly!";
@@ -171,12 +174,16 @@
         if (mModel.get(ACTIVE_TAB) == null) {
             mModel.set(ACTIVE_TAB, tab.getPosition());
         } else {
-            KeyboardAccessoryMetricsRecorder.recordSheetTrigger(
-                    mModel.get(TABS).get(mModel.get(ACTIVE_TAB)).getRecordingType(), MANUAL_CLOSE);
-            mVisibilityDelegate.onOpenKeyboard(); // This will close the active tab gently.
+            closeSheet();
         }
     }
 
+    private void closeSheet() {
+        KeyboardAccessoryMetricsRecorder.recordSheetTrigger(
+                mModel.get(TABS).get(mModel.get(ACTIVE_TAB)).getRecordingType(), MANUAL_CLOSE);
+        mVisibilityDelegate.onOpenKeyboard(); // This will close the active tab gently.
+    }
+
     boolean hasContents() {
         return mModel.get(ACTIONS).size() > 0 || mModel.get(TABS).size() > 0;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java
index 3681f40..d25ea7a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java
@@ -79,7 +79,8 @@
             }
             if (propertyKey == KeyboardAccessoryProperties.ACTIVE_TAB
                     || propertyKey == KeyboardAccessoryProperties.BOTTOM_OFFSET_PX
-                    || propertyKey == KeyboardAccessoryProperties.TAB_SELECTION_CALLBACKS) {
+                    || propertyKey == KeyboardAccessoryProperties.TAB_SELECTION_CALLBACKS
+                    || propertyKey == KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK) {
                 return;
             }
             assert false : "Every property update needs to be handled explicitly!";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernView.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernView.java
new file mode 100644
index 0000000..586cb8d0
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernView.java
@@ -0,0 +1,52 @@
+// 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.
+
+package org.chromium.chrome.browser.autofill.keyboard_accessory;
+
+import android.content.Context;
+import android.support.v7.content.res.AppCompatResources;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+
+import org.chromium.chrome.R;
+
+/**
+ * The Accessory sitting above the keyboard and below the content area. It is used for autofill
+ * suggestions and manual entry points assisting the user in filling forms.
+ */
+class KeyboardAccessoryModernView extends KeyboardAccessoryView {
+    private View mTabsActionsDivider;
+    private View mTabsActionsSpacer;
+    private ImageView mKeyboardToggle;
+
+    /**
+     * Constructor for inflating from XML.
+     */
+    public KeyboardAccessoryModernView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mTabsActionsDivider = findViewById(R.id.tabs_actions_divider);
+        mTabsActionsSpacer = findViewById(R.id.tabs_actions_spacer);
+        mKeyboardToggle = findViewById(R.id.show_keyboard);
+        mKeyboardToggle.setImageDrawable(
+                AppCompatResources.getDrawable(getContext(), R.drawable.ic_keyboard));
+    }
+
+    void setKeyboardToggleVisibility(boolean hasActiveTab) {
+        mKeyboardToggle.setVisibility(hasActiveTab ? VISIBLE : GONE);
+        mTabsActionsSpacer.setVisibility(hasActiveTab ? VISIBLE : GONE);
+        mTabsActionsDivider.setVisibility(hasActiveTab ? GONE : VISIBLE);
+        mActionsView.setVisibility(hasActiveTab ? GONE : VISIBLE);
+    }
+
+    void setShowKeyboardCallback(Runnable showKeyboardCallback) {
+        mKeyboardToggle.setOnClickListener(
+                showKeyboardCallback == null ? null : view -> showKeyboardCallback.run());
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernViewBinder.java
new file mode 100644
index 0000000..8222bce
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernViewBinder.java
@@ -0,0 +1,66 @@
+// 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.
+
+package org.chromium.chrome.browser.autofill.keyboard_accessory;
+
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.ACTIVE_TAB;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Action;
+import org.chromium.chrome.browser.modelutil.PropertyKey;
+import org.chromium.chrome.browser.modelutil.PropertyModel;
+
+/**
+ * Observes {@link KeyboardAccessoryProperties} changes (like a newly available tab) and triggers
+ * the {@link KeyboardAccessoryViewBinder} which will modify the view accordingly.
+ */
+class KeyboardAccessoryModernViewBinder {
+    static class ModernActionViewHolder extends KeyboardAccessoryViewBinder.ActionViewHolder {
+        public ModernActionViewHolder(View actionView) {
+            super(actionView);
+        }
+
+        public static KeyboardAccessoryViewBinder.ActionViewHolder create(
+                ViewGroup parent, @AccessoryAction int viewType) {
+            switch (viewType) {
+                case AccessoryAction.AUTOFILL_SUGGESTION:
+                    return new ModernActionViewHolder(
+                            LayoutInflater.from(parent.getContext())
+                                    .inflate(
+                                            R.layout.keyboard_accessory_suggestion, parent, false));
+                case AccessoryAction.TAB_SWITCHER:
+                    return new ModernActionViewHolder(
+                            LayoutInflater.from(parent.getContext())
+                                    .inflate(R.layout.keyboard_accessory_tabs, parent, false));
+            }
+            return KeyboardAccessoryViewBinder.ActionViewHolder.create(parent, viewType);
+        }
+
+        @Override
+        public void bind(Action action) {
+            if (action.getActionType() == AccessoryAction.TAB_SWITCHER) return;
+            super.bind(action);
+        }
+    }
+
+    public static void bind(
+            PropertyModel model, KeyboardAccessoryView view, PropertyKey propertyKey) {
+        assert view instanceof KeyboardAccessoryModernView;
+        KeyboardAccessoryModernView modernView = (KeyboardAccessoryModernView) view;
+        boolean wasBound = KeyboardAccessoryViewBinder.bindInternal(model, modernView, propertyKey);
+        if (propertyKey == ACTIVE_TAB) {
+            modernView.setKeyboardToggleVisibility(model.get(ACTIVE_TAB) != null);
+        } else if (propertyKey == SHOW_KEYBOARD_CALLBACK) {
+            modernView.setShowKeyboardCallback(model.get(SHOW_KEYBOARD_CALLBACK));
+        } else {
+            assert wasBound : "Every possible property update needs to be handled!";
+        }
+        KeyboardAccessoryViewBinder.requestLayoutPreKitkat(modernView);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryProperties.java
index b9691701..f8e0dbf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryProperties.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryProperties.java
@@ -30,6 +30,8 @@
             new WritableObjectPropertyKey<>();
     static final WritableObjectPropertyKey<TabLayout.OnTabSelectedListener>
             TAB_SELECTION_CALLBACKS = new WritableObjectPropertyKey<>();
+    static final WritableObjectPropertyKey<Runnable> SHOW_KEYBOARD_CALLBACK =
+            new WritableObjectPropertyKey<>();
 
     private KeyboardAccessoryProperties() {}
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java
index 0a85e8152..ae0e16a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java
@@ -28,7 +28,7 @@
  * suggestions and manual entry points assisting the user in filling forms.
  */
 class KeyboardAccessoryView extends LinearLayout {
-    private RecyclerView mActionsView;
+    protected RecyclerView mActionsView;
     private TabLayout mTabLayout;
     private TabLayout.TabLayoutOnPageChangeListener mPageChangeListener;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java
index c7edb1b..6635627 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java
@@ -7,6 +7,7 @@
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.ACTIONS;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.ACTIVE_TAB;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.BOTTOM_OFFSET_PX;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.TABS;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.TAB_SELECTION_CALLBACKS;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.VISIBLE;
@@ -102,6 +103,20 @@
 
     public static void bind(
             PropertyModel model, KeyboardAccessoryView view, PropertyKey propertyKey) {
+        boolean wasBound = bindInternal(model, view, propertyKey);
+        assert wasBound : "Every possible property update needs to be handled!";
+        requestLayoutPreKitkat(view);
+    }
+
+    /**
+     * Tries to bind the given property to the given view by using the value in the given model.
+     * @param model       A {@link PropertyModel}.
+     * @param view        A {@link KeyboardAccessoryView}.
+     * @param propertyKey A {@link PropertyKey}.
+     * @return True if the given propertyKey was bound to the given view.
+     */
+    protected static boolean bindInternal(
+            PropertyModel model, KeyboardAccessoryView view, PropertyKey propertyKey) {
         if (propertyKey == ACTIONS) {
             view.setActionsAdapter(
                     KeyboardAccessoryCoordinator.createActionsAdapter(model.get(ACTIONS)));
@@ -120,11 +135,17 @@
         } else if (propertyKey == TAB_SELECTION_CALLBACKS) {
             // Don't add null as listener. It's a valid state but an invalid argument.
             TabLayout.OnTabSelectedListener listener = model.get(TAB_SELECTION_CALLBACKS);
-            if (listener == null) return;
+            if (listener == null) return true;
             view.setTabSelectionAdapter(listener);
+        } else if (propertyKey == SHOW_KEYBOARD_CALLBACK) {
+            // No binding required.
         } else {
-            assert false : "Every possible property update needs to be handled!";
+            return false;
         }
+        return true;
+    }
+
+    protected static void requestLayoutPreKitkat(View view) {
         // Layout requests happen automatically since Kitkat and redundant requests cause warnings.
         if (view != null && Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
             view.post(() -> {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
index b957e48a..aaf8fe2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
@@ -6,9 +6,12 @@
 
 import android.support.annotation.Nullable;
 import android.view.View;
+import android.view.ViewStub;
 
 import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Provider;
+import org.chromium.ui.DeferredViewStubInflationProvider;
 import org.chromium.ui.DropdownPopupWindow;
 import org.chromium.ui.ViewProvider;
 import org.chromium.ui.base.WindowAndroid;
@@ -28,21 +31,26 @@
      * Initializes the manual filling component. Calls to this class are NoOps until this method is
      * called.
      * @param windowAndroid The window needed to listen to the keyboard and to connect to activity.
-     * @param accessoryViewProvider The view provider for the keyboard accessory bar.
-     * @param viewPagerProvider The view provider for the keyboard accessory bottom sheet.
+     * @param barStub The {@link ViewStub} used to inflate the keyboard accessory bar.
+     * @param sheetStub The {@link ViewStub} used to inflate the keyboard accessory bottom sheet.
      */
-    public void initialize(WindowAndroid windowAndroid,
-            ViewProvider<KeyboardAccessoryView> accessoryViewProvider,
-            ViewProvider<AccessorySheetView> viewPagerProvider) {
-        KeyboardAccessoryCoordinator keyboardAccessory =
-                new KeyboardAccessoryCoordinator(mMediator, accessoryViewProvider);
-        viewPagerProvider.whenLoaded(viewPager -> {
-            accessoryViewProvider.whenLoaded(accessoryView -> {
-                viewPager.addOnPageChangeListener(accessoryView.getPageChangeListener());
-            });
-        });
-        AccessorySheetCoordinator accessorySheet = new AccessorySheetCoordinator(viewPagerProvider);
-        mMediator.initialize(keyboardAccessory, accessorySheet, windowAndroid);
+    public void initialize(WindowAndroid windowAndroid, ViewStub barStub, ViewStub sheetStub) {
+        if (barStub == null || sheetStub == null) return; // The manual filling isn't needed.
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY)) {
+            barStub.setLayoutResource(org.chromium.chrome.R.layout.keyboard_accessory_modern);
+        }
+        initialize(windowAndroid, new DeferredViewStubInflationProvider<>(barStub),
+                new DeferredViewStubInflationProvider<>(sheetStub));
+    }
+
+    @VisibleForTesting
+    void initialize(WindowAndroid windowAndroid, ViewProvider<KeyboardAccessoryView> barProvider,
+            ViewProvider<AccessorySheetView> sheetProvider) {
+        sheetProvider.whenLoaded(accessorySheetView -> barProvider.whenLoaded(accessoryView -> {
+            accessorySheetView.addOnPageChangeListener(accessoryView.getPageChangeListener());
+        }));
+        mMediator.initialize(new KeyboardAccessoryCoordinator(mMediator, barProvider),
+                new AccessorySheetCoordinator(sheetProvider), windowAndroid);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/FeedbackContext.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/FeedbackContext.java
index da5d34f..f7f3373 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/FeedbackContext.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/FeedbackContext.java
@@ -20,7 +20,9 @@
             return new FeedbackContext(activity, client, details, statusMessage)
                     .toString(indentSpaces);
         } catch (JSONException e) {
-            return "{\"error\": \"" + e.getMessage() + "\"}";
+            // Note: it is potentially unsafe to return e.getMessage(): the exception message
+            // could be wrangled and used as an attack vector when arriving at the JSON parser.
+            return "{\"error\": \"Failed to convert feedback context to string.\"}";
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/ui/PaymentRequestUI.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/ui/PaymentRequestUI.java
index 171e2d5..c7bfe64 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/ui/PaymentRequestUI.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/ui/PaymentRequestUI.java
@@ -717,7 +717,7 @@
     }
 
     private void expand(PaymentRequestSection section) {
-        if (!mIsExpandedToFullHeight) {
+        if (!mIsExpandedToFullHeight && section != null) {
             // Container now takes the full height of the screen, animating towards it.
             mRequestView.getLayoutParams().height = LayoutParams.MATCH_PARENT;
             mRequestView.addOnLayoutChangeListener(new SheetEnlargingAnimator(true));
@@ -733,12 +733,11 @@
 
             // Disable all but the first button.
             updateSectionButtons();
-
-            mIsExpandedToFullHeight = true;
         }
 
         // Update the section contents when they're selected.
         mSelectedSection = section;
+        mIsExpandedToFullHeight = mSelectedSection != null;
         if (mSelectedSection == mOrderSummarySection) {
             mClient.getShoppingCart(new Callback<ShoppingCart>() {
                 @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java
index ca0b42a..c243b1d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java
@@ -143,7 +143,7 @@
         super.setTabModelSelector(modelSelector, manager);
         new TabModelSelectorTabObserver(mTabModelSelector) {
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 if (isActive()) unstallImmediately(tab.getId());
             }
         };
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
index 212e8eaa..066417d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
@@ -373,7 +373,7 @@
             }
 
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 getStripLayoutHelper(tab.isIncognito()).tabPageLoadFinished(tab.getId());
             }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/FetchHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/FetchHelper.java
index a8547f9..d6eaff6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/FetchHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/FetchHelper.java
@@ -190,7 +190,7 @@
             }
 
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 setTimeBaselineAndMaybeFetch(tab);
             }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/PageViewTimer.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/PageViewTimer.java
index e975c24b..5b4f9af 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/PageViewTimer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/PageViewTimer.java
@@ -131,7 +131,7 @@
             }
 
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 assert tab == mCurrentTab;
                 mPageDidPaint = true;
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 2d72d26..e0cff14 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -841,7 +841,7 @@
             private boolean mTriggeredPreviewChange;
 
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 // Update the color when the page load finishes.
                 updateColor(tab);
             }
@@ -1059,9 +1059,9 @@
         // Manually generating metrics in case the hidden tab has completely finished loading.
         if (mUsingHiddenTab && !tab.isLoading() && !tab.isShowingErrorPage()) {
             mTabObserver.onPageLoadStarted(tab, params.getUrl());
-            mTabObserver.onPageLoadFinished(tab);
+            mTabObserver.onPageLoadFinished(tab, params.getUrl());
             mTabNavigationEventObserver.onPageLoadStarted(tab, params.getUrl());
-            mTabNavigationEventObserver.onPageLoadFinished(tab);
+            mTabNavigationEventObserver.onPageLoadFinished(tab, params.getUrl());
         }
 
         // No actual load to do if tab already has the exact correct url.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabNavigationEventObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabNavigationEventObserver.java
index 67a9f65..f5c7e53 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabNavigationEventObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabNavigationEventObserver.java
@@ -33,7 +33,7 @@
     }
 
     @Override
-    public void onPageLoadFinished(Tab tab) {
+    public void onPageLoadFinished(Tab tab, String url) {
         CustomTabsConnection.getInstance().notifyNavigationEvent(
                 mSessionToken, CustomTabsCallback.NAVIGATION_FINISHED);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java
index af87d265b..3d90bed3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java
@@ -125,7 +125,7 @@
     }
 
     @Override
-    public void onPageLoadFinished(Tab tab) {
+    public void onPageLoadFinished(Tab tab, String url) {
         long pageLoadFinishedTimestamp = SystemClock.elapsedRealtime();
 
         if (mCurrentState == State.WAITING_LOAD_FINISH && mIntentReceivedTimestamp > 0) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBar.java
index c61b2ef..9d41cb7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBar.java
@@ -4,24 +4,34 @@
 
 package org.chromium.chrome.browser.infobar;
 
+import android.text.SpannableString;
+import android.text.Spanned;
+
+import org.chromium.ui.text.NoUnderlineClickableSpan;
+
 /**
  * An infobar to notify that the generated password was saved.
  */
 public class GeneratedPasswordSavedInfoBar extends ConfirmInfoBar {
     private final int mInlineLinkRangeStart;
     private final int mInlineLinkRangeEnd;
+    private final String mDetailsMessage;
 
     /**
      * Creates and shows the infobar to notify that the generated password was saved.
      * @param iconDrawableId Drawable ID corresponding to the icon that the infobar will show.
      * @param messageText Message to display in the infobar.
+     * @param detailsMessageText  Message containing additional details to be displayed in the
+     * infobar.
      * @param inlineLinkRangeStart The start of the range of the messageText that should be a link.
      * @param inlineLinkRangeEnd The end of the range of the messageText that should be a link.
      * @param buttonLabel String to display on the button.
      */
     public GeneratedPasswordSavedInfoBar(int iconDrawableId, String messageText,
-            int inlineLinkRangeStart, int inlineLinkRangeEnd, String buttonLabel) {
+            String detailsMessageText, int inlineLinkRangeStart, int inlineLinkRangeEnd,
+            String buttonLabel) {
         super(iconDrawableId, null, messageText, null, buttonLabel, null);
+        mDetailsMessage = detailsMessageText;
         mInlineLinkRangeStart = inlineLinkRangeStart;
         mInlineLinkRangeEnd = inlineLinkRangeEnd;
     }
@@ -34,6 +44,10 @@
     @Override
     public void createContent(InfoBarLayout layout) {
         super.createContent(layout);
-        layout.setInlineMessageLink(mInlineLinkRangeStart, mInlineLinkRangeEnd);
+        InfoBarControlLayout detailsMessageLayout = layout.addControlLayout();
+        SpannableString detailsMessageWithLink = new SpannableString(mDetailsMessage);
+        detailsMessageWithLink.setSpan(new NoUnderlineClickableSpan((view) -> onLinkClicked()),
+                mInlineLinkRangeStart, mInlineLinkRangeEnd, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        detailsMessageLayout.addDescription(detailsMessageWithLink);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBarDelegate.java
index f431602e..ea303ecd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBarDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBarDelegate.java
@@ -15,14 +15,17 @@
      * Creates and shows the infobar to notify that the generated password was saved.
      * @param enumeratedIconId Enum ID corresponding to the icon that the infobar will show.
      * @param messageText Message to display in the infobar.
+     * @param detailsMessageText Message containing additional details to be displayed in the
+     * infobar.
      * @param inlineLinkRangeStart The start of the range of the messageText that should be a link.
      * @param inlineLinkRangeEnd The end of the range of the messageText that should be a link.
      * @param buttonLabel String to display on the button.
      */
     @CalledByNative
-    private static InfoBar show(int enumeratedIconId, String messageText, int inlineLinkRangeStart,
-            int inlineLinkRangeEnd, String buttonLabel) {
+    private static InfoBar show(int enumeratedIconId, String messageText, String detailsMessageText,
+            int inlineLinkRangeStart, int inlineLinkRangeEnd, String buttonLabel) {
         return new GeneratedPasswordSavedInfoBar(ResourceId.mapToDrawableId(enumeratedIconId),
-                messageText, inlineLinkRangeStart, inlineLinkRangeEnd, buttonLabel);
+                messageText, detailsMessageText, inlineLinkRangeStart, inlineLinkRangeEnd,
+                buttonLabel);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/OmniboxStartupMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/OmniboxStartupMetrics.java
index 2011034f2e4..cc8cea5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/OmniboxStartupMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/OmniboxStartupMetrics.java
@@ -75,7 +75,7 @@
         mTabModelSelectorTabObserver =
                 new TabModelSelectorTabObserver(mActivity.getTabModelSelector()) {
                     @Override
-                    public void onPageLoadFinished(Tab tab) {
+                    public void onPageLoadFinished(Tab tab, String url) {
                         updateStartupState(StartupState.POST_FIRST_PAGELOAD_FINISHED);
                     }
                 };
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java
index 170e527..2996f368 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java
@@ -106,7 +106,7 @@
                     .keyboard != Configuration.KEYBOARD_NOKEYS;
             mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(mTabModelSelector) {
                 @Override
-                public void onPageLoadFinished(Tab tab) {
+                public void onPageLoadFinished(Tab tab, String url) {
                     recordPageLoadStats(tab);
                 }
             };
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserver.java
index c699261..829bc41 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserver.java
@@ -140,7 +140,7 @@
 
     // Methods from EmptyTabObserver
     @Override
-    public void onPageLoadFinished(Tab tab) {
+    public void onPageLoadFinished(Tab tab, String url) {
         Log.d(TAG, "onPageLoadFinished");
         if (isObservingTab(tab)) {
             mObservedTabs.get(tab.getId()).isLoaded = true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
index e733201..a9137fc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
@@ -794,7 +794,7 @@
          * contents.
          */
         @Override
-        public void onPageLoadFinished(Tab tab) {
+        public void onPageLoadFinished(Tab tab, String url) {
             if (!tab.isBeingRestored()) return;
 
             // We first compute the bitwise tab restore context.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/ManagePasswordsUIProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/ManagePasswordsUIProvider.java
index 64cbc8889..feedf785 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/ManagePasswordsUIProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/ManagePasswordsUIProvider.java
@@ -18,6 +18,7 @@
      * @param activity the activity from which to launch the settings page.
      */
     public void showManagePasswordsUI(Activity activity) {
+        if (activity == null) return;
         // Launch preference activity with SavePasswordsPreferences fragment.
         PreferencesLauncher.launchSettingsPage(activity, SavePasswordsPreferences.class);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
index ab4ba39b..0074745 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
@@ -248,7 +248,7 @@
     public static void addTabObserverForPaymentRequestTab(Tab tab) {
         tab.addObserver(new EmptyTabObserver() {
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 // Notify closing payment app window so as to abort payment if unsecure.
                 WebContents webContents = tab.getWebContents();
                 if (!OriginSecurityChecker.isOriginSecure(webContents.getLastCommittedUrl())
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java
index 8d5b44b..84b4c8f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java
@@ -11,13 +11,13 @@
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 
-import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.CalledByNative;
+import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.preferences.autofill.AutofillPaymentMethodsFragment;
 import org.chromium.chrome.browser.preferences.autofill.AutofillProfilesFragment;
-import org.chromium.chrome.browser.preferences.password.SavePasswordsPreferences;
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.ui.base.WindowAndroid;
 
 import java.lang.ref.WeakReference;
 
@@ -100,8 +100,12 @@
     }
 
     @CalledByNative
-    private static void showPasswordSettings() {
-        launchSettingsPage(ContextUtils.getApplicationContext(), SavePasswordsPreferences.class);
+    private static void showPasswordSettings(WebContents webContents) {
+        WindowAndroid window = webContents.getTopLevelNativeWindow();
+        if (window == null) return;
+        WeakReference<Activity> currentActivity = window.getActivity();
+        AppHooks.get().createManagePasswordsUIProvider().showManagePasswordsUI(
+                currentActivity.get());
     }
 
     private static void showSettingSubpage(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java
index 2b02da8..eb05ddb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java
@@ -713,7 +713,7 @@
         int contentType = mCategory.getContentSettingsType();
         PreferenceScreen screen = getPreferenceScreen();
 
-        // Find all preferencs on the current preference screen. Some preferences are
+        // Find all preferences on the current preference screen. Some preferences are
         // not needed for the current category and will be removed in the steps below.
         ChromeSwitchPreference binaryToggle =
                 (ChromeSwitchPreference) screen.findPreference(BINARY_TOGGLE_KEY);
@@ -724,44 +724,19 @@
         Preference explainProtectedMediaKey = screen.findPreference(EXPLAIN_PROTECTED_MEDIA_KEY);
         PreferenceGroup allowedGroup = (PreferenceGroup) screen.findPreference(ALLOWED_GROUP);
         PreferenceGroup blockedGroup = (PreferenceGroup) screen.findPreference(BLOCKED_GROUP);
-
+        boolean permissionBlockedByOs = mCategory.showPermissionBlockedMessage(getActivity());
         // For these categories, no binary, tri-state or custom toggles should be shown.
-        boolean hideAllToggles = mCategory.showSites(SiteSettingsCategory.Type.ALL_SITES)
+        boolean hideMainToggles = mCategory.showSites(SiteSettingsCategory.Type.ALL_SITES)
                 || mCategory.showSites(SiteSettingsCategory.Type.USE_STORAGE)
-                || mCategory.showPermissionBlockedMessage(getActivity());
+                || (permissionBlockedByOs
+                           && !ChromeFeatureList.isEnabled(
+                                      ChromeFeatureList.ANDROID_SITE_SETTINGS_UI));
+        boolean hideSecondaryToggles = hideMainToggles || permissionBlockedByOs;
 
-        if (hideAllToggles) {
+        if (hideMainToggles) {
             screen.removePreference(binaryToggle);
             screen.removePreference(triStateToggle);
-            screen.removePreference(thirdPartyCookies);
-            screen.removePreference(notificationsVibrate);
-            screen.removePreference(explainProtectedMediaKey);
-            screen.removePreference(allowedGroup);
-            screen.removePreference(blockedGroup);
-
-            if (mCategory.showPermissionBlockedMessage(getActivity())) {
-                // Show the link to system settings since permission is disabled.
-                ChromeBasePreference osWarning = new ChromeBasePreference(getActivity(), null);
-                ChromeBasePreference osWarningExtra = new ChromeBasePreference(getActivity(), null);
-                mCategory.configurePermissionIsOffPreferences(
-                        osWarning, osWarningExtra, getActivity(), true);
-                if (osWarning.getTitle() != null) {
-                    screen.addPreference(osWarning);
-                }
-                if (osWarningExtra.getTitle() != null) {
-                    screen.addPreference(osWarningExtra);
-                }
-            }
-
-            // Since all preferences are hidden, there's nothing to do further and we can
-            // simply return.
-            return;
-        }
-
-        // Now show and configure the binary toggle or the tri-state toggle, but not both.
-        // No early return in either case since we also need to configure the category
-        // specific toggles (e.g. third-party cookie) below.
-        if (mRequiresTriStateSetting) {
+        } else if (mRequiresTriStateSetting) {
             screen.removePreference(binaryToggle);
             configureTriStateToggle(triStateToggle, contentType);
         } else {
@@ -769,6 +744,21 @@
             configureBinaryToggle(binaryToggle, contentType);
         }
 
+        if (permissionBlockedByOs) {
+            maybeShowOsWarning(screen);
+        }
+
+        if (hideSecondaryToggles) {
+            screen.removePreference(thirdPartyCookies);
+            screen.removePreference(notificationsVibrate);
+            screen.removePreference(explainProtectedMediaKey);
+            screen.removePreference(allowedGroup);
+            screen.removePreference(blockedGroup);
+            // Since all preferences are hidden, there's nothing to do further and we can
+            // simply return.
+            return;
+        }
+
         // Configure/hide the third-party cookie toggle, as needed.
         if (mCategory.showSites(SiteSettingsCategory.Type.COOKIES)) {
             thirdPartyCookies.setOnPreferenceChangeListener(this);
@@ -802,6 +792,25 @@
         blockedGroup.setOnPreferenceClickListener(this);
     }
 
+    private void maybeShowOsWarning(PreferenceScreen screen) {
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_SITE_SETTINGS_UI)
+                && isBlocked()) {
+            return;
+        }
+
+        // Show the link to system settings since permission is disabled.
+        ChromeBasePreference osWarning = new ChromeBasePreference(getActivity(), null);
+        ChromeBasePreference osWarningExtra = new ChromeBasePreference(getActivity(), null);
+        mCategory.configurePermissionIsOffPreferences(
+                osWarning, osWarningExtra, getActivity(), true);
+        if (osWarning.getTitle() != null) {
+            screen.addPreference(osWarning);
+        }
+        if (osWarningExtra.getTitle() != null) {
+            screen.addPreference(osWarningExtra);
+        }
+    }
+
     private void configureTriStateToggle(
             TriStateSiteSettingsPreference triStateToggle, int contentType) {
         triStateToggle.setOnPreferenceChangeListener(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsCategory.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsCategory.java
index d80ee897..75d8e46 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsCategory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SiteSettingsCategory.java
@@ -404,9 +404,14 @@
      * @param plural Whether it applies to one per-app permission or multiple.
      */
     protected String getMessageForEnablingOsPerAppPermission(Activity activity, boolean plural) {
-        return activity.getResources().getString(plural
-                ? R.string.android_permission_off_plural
-                : R.string.android_permission_off);
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_SITE_SETTINGS_UI)) {
+            return activity.getResources().getString(plural
+                            ? R.string.android_permission_also_off_plural
+                            : R.string.android_permission_also_off);
+        } else {
+            return activity.getResources().getString(plural ? R.string.android_permission_off_plural
+                                                            : R.string.android_permission_off);
+        }
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java b/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java
index 4df56251..58516a1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java
@@ -234,7 +234,7 @@
             }
 
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 showInfoBarIfApplicable(tab, siteId, this);
             }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java
index e524b1a2..37d86c2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java
@@ -43,7 +43,7 @@
     public void onPageLoadStarted(Tab tab, String url) { }
 
     @Override
-    public void onPageLoadFinished(Tab tab) { }
+    public void onPageLoadFinished(Tab tab, String url) {}
 
     @Override
     public void onPageLoadFailed(Tab tab, int errorCode) { }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/SadTab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/SadTab.java
index 66e15e7c..f0b7cd0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/SadTab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/SadTab.java
@@ -150,7 +150,7 @@
     }
 
     @Override
-    public void onPageLoadFinished(Tab tab) {
+    public void onPageLoadFinished(Tab tab, String url) {
         // Reset the succressiveRefresh counter after successfully loading a page.
         mSadTabSuccessiveRefreshCounter = 0;
         removeIfPresent();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 1652ac78..35f66c51 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -422,7 +422,7 @@
 
             if (didFinishLoad) {
                 // Simulate the PAGE_LOAD_FINISHED notification that we did not get.
-                didFinishPageLoad();
+                didFinishPageLoad(url);
             }
         }
     };
@@ -890,7 +890,7 @@
         if (isLoading()) {
             RewindableIterator<TabObserver> observers = getTabObservers();
             while (observers.hasNext()) {
-                observers.next().onPageLoadFinished(this);
+                observers.next().onPageLoadFinished(this, getUrl());
             }
         }
         if (getWebContents() != null) getWebContents().stop();
@@ -1480,13 +1480,14 @@
 
     /**
      * Called when a page has finished loading.
+     * @param url URL that was loaded.
      */
-    protected void didFinishPageLoad() {
+    protected void didFinishPageLoad(String url) {
         mIsTabStateDirty = true;
         updateTitle();
         updateFullscreenEnabledState();
 
-        for (TabObserver observer : mObservers) observer.onPageLoadFinished(this);
+        for (TabObserver observer : mObservers) observer.onPageLoadFinished(this, url);
         mIsBeingRestored = false;
 
         // TODO(crbug.com/889682): Consider moving the rest of this function to a Tab User data.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabObserver.java
index 81328503..ea6897d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabObserver.java
@@ -86,8 +86,9 @@
      * Called when a tab has finished loading a page.
      *
      * @param tab The notifying {@link Tab}.
+     * @param url The committed URL that was navigated to.
      */
-    void onPageLoadFinished(Tab tab);
+    void onPageLoadFinished(Tab tab, String url);
 
     /**
      * Called when a tab has failed loading a page.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java
index 82f90f7..c6684ebe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java
@@ -104,7 +104,7 @@
             }
 
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 // Handle the case where a commit or prerender swap notification failed to arrive
                 // and the enable fullscreen message was never enqueued.
                 scheduleEnableFullscreenLoadDelayIfNecessary();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java
index 8648e81c..3b4a2d14 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java
@@ -389,7 +389,7 @@
 
     /** Called when the correspoding tab completes a page load. */
     @Override
-    public void onPageLoadFinished(Tab tab) {
+    public void onPageLoadFinished(Tab tab, String url) {
         // Record only tab restores that the user became aware of. If the restore is triggered
         // speculatively and completes before the user switches to the tab, then this case is
         // reflected in Tab.StatusWhenSwitchedBackToForeground metric.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
index 98ed7cabf..15db351 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
@@ -177,7 +177,7 @@
             if (mTab.getNativePage() != null) {
                 mTab.pushNativePageStateToNavigationEntry();
             }
-            if (isMainFrame) mTab.didFinishPageLoad();
+            if (isMainFrame) mTab.didFinishPageLoad(validatedUrl);
             PolicyAuditor auditor = AppHooks.get().getPolicyAuditor();
             auditor.notifyAuditEvent(
                     mTab.getApplicationContext(), AuditEvent.OPEN_URL_SUCCESS, validatedUrl, "");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
index e450114..8c4f830 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
@@ -181,7 +181,7 @@
             }
 
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 mUma.onPageLoadFinished(tab.getId());
             }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 207fc17..226f721 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -451,7 +451,7 @@
             }
 
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 if (tab.isShowingErrorPage()) {
                     handleIPHForErrorPageShown(tab);
                     return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/ShareButton.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/ShareButton.java
index 9c7fc0ce..0189d3d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/ShareButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/ShareButton.java
@@ -59,7 +59,7 @@
     void setTabModelSelector(TabModelSelector tabModelSelector) {
         mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(tabModelSelector) {
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 if (tab == null) return;
                 setEnabled(shouldEnableShare(tab));
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappSplashScreenController.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappSplashScreenController.java
index acc075a2..8072bcbd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappSplashScreenController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappSplashScreenController.java
@@ -144,7 +144,7 @@
     }
 
     @Override
-    public void onPageLoadFinished(Tab tab) {
+    public void onPageLoadFinished(Tab tab, String url) {
         if (canHideSplashScreen()) {
             hideSplashScreenOnDrawingFinished(tab, WebappUma.SplashScreenHidesReason.LOAD_FINISHED);
         }
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 4ad6a7d..24ac097 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1155,6 +1155,12 @@
       <message name="IDS_ANDROID_PERMISSION_OFF" desc="Text at the top of the Website list, explaining to the user that a permission, such as the location service, is turned off. Contains a link to the settings menu to change it.">
         Turn on permission for Chrome in <ph name="BEGIN_LINK">&lt;link&gt;</ph>Android Settings<ph name="END_LINK">&lt;/link&gt;</ph>.
       </message>
+      <message name="IDS_ANDROID_PERMISSION_ALSO_OFF" desc="The message to show when a permission needs to be turned on not just in Chrome, but also in Android settings.">
+        You also need to turn this permission on for Chrome. See <ph name="BEGIN_LINK">&lt;link&gt;</ph>Android Settings<ph name="END_LINK">&lt;/link&gt;</ph> for details.
+      </message>
+      <message name="IDS_ANDROID_PERMISSION_ALSO_OFF_PLURAL" desc="The message to show when a permission needs to be turned on not just in Chrome, but also in Android settings.">
+        You also need to turn these permissions on for Chrome. See <ph name="BEGIN_LINK">&lt;link&gt;</ph>Android Settings<ph name="END_LINK">&lt;/link&gt;</ph> for details.
+      </message>
       <message name="IDS_ANDROID_LOCATION_OFF_GLOBALLY" desc="The message to show when Location has been turned off globally in Android. Contains a link to the settings menu to enable location.">
         Location access is off for this device. Turn it on in <ph name="BEGIN_LINK">&lt;link&gt;</ph>Android Settings<ph name="END_LINK">&lt;/link&gt;</ph>.
       </message>
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index fc9e49ed..c41b9f9a 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -113,6 +113,8 @@
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryProperties.java",
+  "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernView.java",
+  "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernViewBinder.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java",
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java",
@@ -2150,6 +2152,7 @@
   "javatests/src/org/chromium/chrome/browser/preferences/developer/TracingPreferencesTest.java",
   "javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java",
   "javatests/src/org/chromium/chrome/browser/preferences/privacy/BrowsingDataBridgeTest.java",
+  "javatests/src/org/chromium/chrome/browser/preferences/privacy/BrowsingDataTest.java",
   "javatests/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferencesTest.java",
   "javatests/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferencesBasicTest.java",
   "javatests/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferencesManagerNativeTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/CopylessPasteTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/CopylessPasteTest.java
index f48ebc5..03c4c6b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/CopylessPasteTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/CopylessPasteTest.java
@@ -116,8 +116,8 @@
     @Feature({"CopylessPaste"})
     public void testInvalidScheme() throws InterruptedException, TimeoutException {
         // CopylessPaste only parses http and https.
-        mActivityTestRule.loadUrl("chrome://newtab");
-        mActivityTestRule.loadUrl("chrome://about");
+        mActivityTestRule.loadUrl(UrlConstants.NTP_NON_NATIVE_URL);
+        mActivityTestRule.loadUrl(UrlConstants.ABOUT_URL);
         Assert.assertEquals(0, mCallbackHelper.getCallCount());
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/PopularUrlsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/PopularUrlsTest.java
index df2523fe..1d96048 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/PopularUrlsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/PopularUrlsTest.java
@@ -240,7 +240,7 @@
 
         tab.addObserver(new EmptyTabObserver() {
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 loadedCallback.notifyCalled();
             }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabThemeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabThemeTest.java
index 962a03c..345b564 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabThemeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabThemeTest.java
@@ -119,7 +119,7 @@
         assertColorsEqual(THEME_COLOR, getThemeColor(tab));
 
         // Navigate to a native page from a themed page.
-        mActivityTestRule.loadUrl("chrome://newtab");
+        mActivityTestRule.loadUrl("chrome://newtab/");
         // WebContents does not set theme color for native pages, so don't wait for the call.
         int nativePageThemeColor = ThreadUtils.runOnUiThreadBlocking(
                 () -> tab.getNativePage().getThemeColor());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
index 5c3a790..0369698 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -79,7 +79,6 @@
 import org.chromium.content_public.browser.test.util.TouchCommon;
 import org.chromium.content_public.browser.test.util.UiUtils;
 import org.chromium.content_public.common.ContentSwitches;
-import org.chromium.content_public.common.ContentUrlConstants;
 import org.chromium.net.test.EmbeddedTestServer;
 import org.chromium.ui.test.util.UiRestriction;
 
@@ -530,7 +529,7 @@
 
         int initialTabCount = mActivityTestRule.getActivity().getCurrentTabModel().getCount();
         ChromeTabUtils.fullyLoadUrlInNewTab(InstrumentationRegistry.getInstrumentation(),
-                mActivityTestRule.getActivity(), ContentUrlConstants.ABOUT_BLANK_URL, false);
+                mActivityTestRule.getActivity(), UrlConstants.CHROME_BLANK_URL, false);
         ThreadUtils.runOnUiThreadBlocking(
                 () -> { mActivityTestRule.getActivity().getLayoutManager().showOverview(false); });
 
@@ -1570,7 +1569,7 @@
     @DisabledTest(message = "crbug.com/882003")
     public void testToolbarSwipeNextThenPrevTab() throws InterruptedException, TimeoutException {
         ChromeTabUtils.fullyLoadUrlInNewTab(InstrumentationRegistry.getInstrumentation(),
-                mActivityTestRule.getActivity(), ContentUrlConstants.ABOUT_BLANK_URL, false);
+                mActivityTestRule.getActivity(), UrlConstants.CHROME_BLANK_URL, false);
         ChromeTabUtils.switchTabInCurrentTabModel(mActivityTestRule.getActivity(), 0);
         UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
 
@@ -1593,9 +1592,9 @@
     public void testToolbarSwipeNextThenPrevTabIncognito()
             throws InterruptedException, TimeoutException {
         ChromeTabUtils.fullyLoadUrlInNewTab(InstrumentationRegistry.getInstrumentation(),
-                mActivityTestRule.getActivity(), ContentUrlConstants.ABOUT_BLANK_URL, true);
+                mActivityTestRule.getActivity(), UrlConstants.CHROME_BLANK_URL, true);
         ChromeTabUtils.fullyLoadUrlInNewTab(InstrumentationRegistry.getInstrumentation(),
-                mActivityTestRule.getActivity(), ContentUrlConstants.ABOUT_BLANK_URL, true);
+                mActivityTestRule.getActivity(), UrlConstants.CHROME_BLANK_URL, true);
         mActivityTestRule.getActivity().getTabModelSelector().selectModel(true);
         ChromeTabUtils.switchTabInCurrentTabModel(mActivityTestRule.getActivity(), 0);
         UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
@@ -1952,7 +1951,7 @@
                     pageLoadedCallbacks[index] = pageLoadCallback;
                     currentTab.addObserver(new EmptyTabObserver() {
                         @Override
-                        public void onPageLoadFinished(Tab tab) {
+                        public void onPageLoadFinished(Tab tab, String url) {
                             pageLoadCallback.notifyCalled();
                             tab.removeObserver(this);
                         }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java
index 3e398ec4..e62514dc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java
@@ -208,7 +208,7 @@
         try {
             TestFileUtil.createNewHtmlFile(
                     file, target, "<img src=\"" + createContentUrl(target) + "\">");
-            mActivityTestRule.loadUrl("file:///" + file.getAbsolutePath());
+            mActivityTestRule.loadUrl("file://" + file.getAbsolutePath());
             ensureResourceRequestCountInContentProvider(target, 0);
         } finally {
             TestFileUtil.deleteFile(file);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
index 003e9117..f59e330c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
@@ -63,6 +63,7 @@
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @EnableFeatures({ChromeFeatureList.PASSWORDS_KEYBOARD_ACCESSORY,
+        ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY,
         // TODO(crbug.com/894428): Remove and use the embedded test server instead of data urls.
         ChromeFeatureList.AUTOFILL_ALLOW_NON_HTTP_ACTIVATION})
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
index 1088392..a0b6df3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
@@ -187,7 +187,7 @@
                 isItemPresentInBookmarkList(TEST_PAGE_TITLE_GOOGLE));
         final View tile = getViewWithText(mItemsContainer, TEST_PAGE_TITLE_GOOGLE);
         ChromeTabUtils.waitForTabPageLoaded(mActivityTestRule.getActivity().getActivityTab(),
-                () -> TouchCommon.singleClickView(tile));
+                mTestPage, () -> TouchCommon.singleClickView(tile));
         Assert.assertEquals(TEST_PAGE_TITLE_GOOGLE,
                 mActivityTestRule.getActivity().getActivityTab().getTitle());
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 8e1b5025..cbd6bd50e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -1226,7 +1226,7 @@
         final CallbackHelper pageLoadFinishedHelper = new CallbackHelper();
         tab.addObserver(new EmptyTabObserver() {
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 pageLoadFinishedHelper.notifyCalled();
             }
         });
@@ -1288,7 +1288,7 @@
             }
 
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 pageLoadFinishedHelper.notifyCalled();
             }
         });
@@ -1328,7 +1328,7 @@
             }
 
             @Override
-            public void onPageLoadFinished(Tab tab) {
+            public void onPageLoadFinished(Tab tab, String url) {
                 pageLoadFinishedHelper.notifyCalled();
             }
         });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/DistillabilityServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/DistillabilityServiceTest.java
index 7373cfb6..c2720644 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/DistillabilityServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/DistillabilityServiceTest.java
@@ -89,7 +89,7 @@
 
         // Navigate to a native page.
         int curCallCount = finishHelper.getCallCount();
-        mActivityTestRule.loadUrl("chrome://history");
+        mActivityTestRule.loadUrl("chrome://history/");
         finishHelper.waitForCallback(curCallCount, 1);
         Assert.assertEquals(0, readerShownCallbackHelper.getCallCount());
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
index 2f09829..71b9f62 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
@@ -105,7 +105,7 @@
         }
 
         @Override
-        public void onPageLoadFinished(Tab tab) {
+        public void onPageLoadFinished(Tab tab, String url) {
             mFinishCallback.notifyCalled();
         }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
index 5992855..9a89f3e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -336,7 +336,7 @@
                 (LocationBarLayout) mActivityTestRule.getActivity().findViewById(R.id.location_bar);
         OmniboxTestUtils.waitForOmniboxSuggestions(locationBar);
 
-        ChromeTabUtils.waitForTabPageLoaded(mTab, new Runnable() {
+        ChromeTabUtils.waitForTabPageLoaded(mTab, null, new Runnable() {
             @Override
             public void run() {
                 KeyUtils.singleKeyEventView(InstrumentationRegistry.getInstrumentation(), urlBar,
@@ -353,7 +353,7 @@
     @Feature({"NewTabPage", "FeedNewTabPage"})
     @ParameterAnnotations.UseMethodParameter(InterestFeedParams.class)
     public void testClickMostVisitedItem(boolean interestFeedEnabled) throws InterruptedException {
-        ChromeTabUtils.waitForTabPageLoaded(mTab, new Runnable() {
+        ChromeTabUtils.waitForTabPageLoaded(mTab, mSiteSuggestions.get(0).url, new Runnable() {
             @Override
             public void run() {
                 View mostVisitedItem = mTileGridLayout.getChildAt(0);
@@ -422,7 +422,7 @@
     public void testUrlFocusAnimationsDisabledOnLoad(boolean interestFeedEnabled)
             throws InterruptedException {
         Assert.assertFalse(getUrlFocusAnimationsDisabled());
-        ChromeTabUtils.waitForTabPageLoaded(mTab, new Runnable() {
+        ChromeTabUtils.waitForTabPageLoaded(mTab, mTestServer.getURL(TEST_PAGE), new Runnable() {
             @Override
             public void run() {
                 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@@ -480,7 +480,7 @@
             final CallbackHelper loadedCallback = new CallbackHelper();
             mTab.addObserver(new EmptyTabObserver() {
                 @Override
-                public void onPageLoadFinished(Tab tab) {
+                public void onPageLoadFinished(Tab tab, String url) {
                     loadedCallback.notifyCalled();
                     tab.removeObserver(this);
                 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerViewTest.java
index 3663fda..2ea4cb0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerViewTest.java
@@ -152,7 +152,7 @@
         SnippetArticle suggestion = suggestions.get(suggestions.size() - 1);
         int suggestionPosition = getLastCardPosition();
         final View suggestionView = getViewHolderAtPosition(suggestionPosition).itemView;
-        ChromeTabUtils.waitForTabPageLoaded(mTab, () -> {
+        ChromeTabUtils.waitForTabPageLoaded(mTab, suggestion.mUrl, () -> {
             TestTouchUtils.performClickOnMainSync(
                     InstrumentationRegistry.getInstrumentation(), suggestionView);
         });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java
index b36a86bf..36fa9277 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java
@@ -105,8 +105,8 @@
                     Uri.parse(mActivityTestRule.getActivity().getActivityTab().getUrl()));
 
             // Click homepage button.
-            ChromeTabUtils.waitForTabPageLoaded(
-                    mActivityTestRule.getActivity().getActivityTab(), new Runnable() {
+            ChromeTabUtils.waitForTabPageLoaded(mActivityTestRule.getActivity().getActivityTab(),
+                    TestPartnerBrowserCustomizationsProvider.HOMEPAGE_URI, new Runnable() {
                         @Override
                         public void run() {
                             View homeButton =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/privacy/BrowsingDataTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/privacy/BrowsingDataTest.java
new file mode 100644
index 0000000..199b6b0
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/privacy/BrowsingDataTest.java
@@ -0,0 +1,151 @@
+// 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.
+
+package org.chromium.chrome.browser.preferences.privacy;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.browsing_data.BrowsingDataType;
+import org.chromium.chrome.browser.browsing_data.ClearBrowsingDataTab;
+import org.chromium.chrome.browser.browsing_data.TimePeriod;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.content_public.browser.test.util.JavaScriptUtils;
+import org.chromium.net.test.EmbeddedTestServer;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Integration tests for browsing data deletion.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class BrowsingDataTest {
+    private static final String TEST_FILE = "/content/test/data/browsing_data/site_data.html";
+
+    private EmbeddedTestServer mTestServer;
+    private String mUrl;
+
+    @Rule
+    public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
+            new ChromeActivityTestRule<>(ChromeActivity.class);
+
+    @Before
+    public void setUp() throws Exception {
+        mActivityTestRule.startMainActivityOnBlankPage();
+        mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
+        mUrl = mTestServer.getURL(TEST_FILE);
+    }
+
+    private void clearBrowsingData(int dataType, int timePeriod)
+            throws InterruptedException, TimeoutException {
+        CallbackHelper helper = new CallbackHelper();
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            BrowsingDataBridge.getInstance().clearBrowsingData(
+                    helper::notifyCalled, new int[] {dataType}, timePeriod);
+        });
+        helper.waitForCallback(0);
+    }
+
+    private int getCookieCount() throws Exception {
+        String[] out = {""};
+        BrowsingDataCounterBridge[] counter = {null};
+        CallbackHelper helper = new CallbackHelper();
+        BrowsingDataCounterBridge.BrowsingDataCounterCallback callback = (result) -> {
+            out[0] = result;
+            helper.notifyCalled();
+        };
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            counter[0] = new BrowsingDataCounterBridge(
+                    callback, BrowsingDataType.COOKIES, ClearBrowsingDataTab.ADVANCED);
+        });
+        helper.waitForCallback(0);
+        // The counter returns a result like "3 sites" or "None".
+        if (out[0].equals("None")) return 0;
+        return Integer.parseInt(out[0].replaceAll("[^0-9]", ""));
+    }
+
+    private String runJavascriptAsync(String type) throws Exception {
+        return JavaScriptUtils.runJavascriptWithAsyncResult(
+                mActivityTestRule.getWebContents(), type);
+    }
+
+    /**
+     * Test cookies deletion.
+     */
+    @Test
+    @SmallTest
+    public void testCookiesDeleted() throws Exception {
+        Assert.assertEquals(0, getCookieCount());
+        mActivityTestRule.loadUrl(mUrl);
+        Assert.assertEquals("false", runJavascriptAsync("hasCookie()"));
+
+        runJavascriptAsync("setCookie()");
+        Assert.assertEquals("true", runJavascriptAsync("hasCookie()"));
+        Assert.assertEquals(1, getCookieCount());
+
+        clearBrowsingData(BrowsingDataType.COOKIES, TimePeriod.LAST_HOUR);
+        Assert.assertEquals("false", runJavascriptAsync("hasCookie()"));
+        Assert.assertEquals(0, getCookieCount());
+    }
+
+    /**
+     * Test site data deletion.
+     */
+    @Test
+    @SmallTest
+    public void testSiteDataDeleted() throws Exception {
+        // TODO(dullweber): Investigate, why WebSql fails this test.
+        List<String> siteData = Arrays.asList("LocalStorage", "ServiceWorker", "CacheStorage",
+                "IndexedDb", "FileSystem" /*, "WebSql"*/);
+        mActivityTestRule.loadUrl(mUrl);
+
+        for (String type : siteData) {
+            Assert.assertEquals(type, 0, getCookieCount());
+            Assert.assertEquals(type, "false", runJavascriptAsync("has" + type + "()"));
+
+            runJavascriptAsync("set" + type + "()");
+            Assert.assertEquals(type, 1, getCookieCount());
+            Assert.assertEquals(type, "true", runJavascriptAsync("has" + type + "()"));
+
+            clearBrowsingData(BrowsingDataType.COOKIES, TimePeriod.LAST_HOUR);
+            Assert.assertEquals(type, 0, getCookieCount());
+            Assert.assertEquals(type, "false", runJavascriptAsync("has" + type + "()"));
+
+            // Some types create data by checking for them, so we need to do a cleanup at the end.
+            clearBrowsingData(BrowsingDataType.COOKIES, TimePeriod.LAST_HOUR);
+        }
+    }
+
+    /**
+     * Test history deletion.
+     */
+    @Test
+    @SmallTest
+    public void testHistoryDeleted() throws Exception {
+        Assert.assertEquals(0, getCookieCount());
+        mActivityTestRule.loadUrlInNewTab(mUrl);
+        Assert.assertEquals("false", runJavascriptAsync("hasHistory()"));
+
+        runJavascriptAsync("setHistory()");
+        Assert.assertEquals("true", runJavascriptAsync("hasHistory()"));
+
+        clearBrowsingData(BrowsingDataType.HISTORY, TimePeriod.LAST_HOUR);
+        Assert.assertEquals("false", runJavascriptAsync("hasHistory()"));
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/UkmTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/UkmTest.java
index 134ef80..ccf0428c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/UkmTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/UkmTest.java
@@ -38,7 +38,7 @@
     @Rule
     public SyncTestRule mSyncTestRule = new SyncTestRule();
 
-    private static final String DEBUG_PAGE = "chrome://ukm";
+    private static final String DEBUG_PAGE = "chrome://ukm/";
 
     @Before
     public void setUp() throws InterruptedException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabTestUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabTestUtils.java
index 0433244..2196ce8d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabTestUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabTestUtils.java
@@ -37,7 +37,7 @@
      */
     public static void simulatePageLoadFinished(Tab tab) {
         RewindableIterator<TabObserver> observers = tab.getTabObservers();
-        while (observers.hasNext()) observers.next().onPageLoadFinished(tab);
+        while (observers.hasNext()) observers.next().onPageLoadFinished(tab, tab.getUrl());
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreatorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreatorTest.java
index 0c99b64..3bcf1196 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreatorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreatorTest.java
@@ -81,7 +81,7 @@
         Assert.assertFalse(bgTab.isLoading());
 
         // Switch tabs and verify that the tab is loaded as it gets foregrounded.
-        ChromeTabUtils.waitForTabPageLoaded(bgTab, new Runnable() {
+        ChromeTabUtils.waitForTabPageLoaded(bgTab, mTestServer.getURL(TEST_PATH), new Runnable() {
             @Override
             public void run() {
                 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java
index e0c144a4..7029941 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserNavigationTest.java
@@ -128,10 +128,11 @@
      * navigation. This is desirable since we are testing navigation transitions end-to-end.
      */
     private void navigateTo(final @Page int to) throws InterruptedException {
-        ChromeTabUtils.waitForTabPageLoaded(mTestRule.getActivity().getActivityTab(), () -> {
-            mVrBrowserTestFramework.runJavaScriptOrFail(
-                    "window.location.href = '" + getUrl(to) + "';", POLL_TIMEOUT_SHORT_MS);
-        }, POLL_TIMEOUT_LONG_MS);
+        ChromeTabUtils.waitForTabPageLoaded(
+                mTestRule.getActivity().getActivityTab(), getUrl(to), () -> {
+                    mVrBrowserTestFramework.runJavaScriptOrFail(
+                            "window.location.href = '" + getUrl(to) + "';", POLL_TIMEOUT_SHORT_MS);
+                }, POLL_TIMEOUT_LONG_MS);
     }
 
     private void enterFullscreenOrFail(WebContents webContents)
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrFeedbackInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrFeedbackInfoBarTest.java
index b0b9918..3891b8c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrFeedbackInfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrFeedbackInfoBarTest.java
@@ -203,10 +203,12 @@
                 TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
 
         // Exit presentation mode by navigating to a different url.
-        ChromeTabUtils.waitForTabPageLoaded(mTestRule.getActivity().getActivityTab(), () -> {
-            mVrBrowserTestFramework.runJavaScriptOrFail(
-                    "window.location.href = '" + TEST_PAGE_2D_URL + "';", POLL_TIMEOUT_SHORT_MS);
-        }, POLL_TIMEOUT_LONG_MS);
+        ChromeTabUtils.waitForTabPageLoaded(
+                mTestRule.getActivity().getActivityTab(), TEST_PAGE_2D_URL, () -> {
+                    mVrBrowserTestFramework.runJavaScriptOrFail(
+                            "window.location.href = '" + TEST_PAGE_2D_URL + "';",
+                            POLL_TIMEOUT_SHORT_MS);
+                }, POLL_TIMEOUT_LONG_MS);
 
         // Exiting VR should prompt for feedback since 2D browsing was performed after.
         VrBrowserTransitionUtils.forceExitVr();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java
index 816a266e..ab5038b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java
@@ -395,12 +395,9 @@
     public int loadUrlAndAwaitInitialization(String url, int timeoutSec)
             throws InterruptedException {
         int result = mRule.loadUrl(url, timeoutSec);
-        // TODO(https://crbug.com/894796): Remove the isInitializationComplete undefined check once
-        // loadUrl is fixed.
         Assert.assertTrue("Timed out waiting for JavaScript test initialization",
-                pollJavaScriptBoolean("(typeof isInitializationComplete !== 'undefined') && "
-                                + "isInitializationComplete()",
-                        POLL_TIMEOUT_LONG_MS, mRule.getWebContents()));
+                pollJavaScriptBoolean("isInitializationComplete()", POLL_TIMEOUT_LONG_MS,
+                        mRule.getWebContents()));
         return result;
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDeferredStartupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDeferredStartupTest.java
index cd806b0..2aa02e19 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDeferredStartupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDeferredStartupTest.java
@@ -32,7 +32,7 @@
         private boolean mIsPageLoadFinished;
 
         @Override
-        public void onPageLoadFinished(Tab tab) {
+        public void onPageLoadFinished(Tab tab, String url) {
             mIsPageLoadFinished = true;
         }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryControllerTest.java
index 5e62996a..c18afee0 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryControllerTest.java
@@ -32,6 +32,7 @@
 import org.chromium.base.metrics.test.ShadowRecordHistogram;
 import org.chromium.base.task.test.CustomShadowAsyncTask;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Action;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.PropertyProvider;
 import org.chromium.chrome.browser.modelutil.ListObservable;
@@ -40,6 +41,8 @@
 import org.chromium.chrome.browser.modelutil.PropertyObservable.PropertyObserver;
 import org.chromium.chrome.test.util.browser.modelutil.FakeViewProvider;
 
+import java.util.HashMap;
+
 /**
  * Controller tests for the keyboard accessory component.
  */
@@ -56,7 +59,7 @@
     @Mock
     private KeyboardAccessoryCoordinator.VisibilityDelegate mMockVisibilityDelegate;
     @Mock
-    private KeyboardAccessoryView mMockView;
+    private KeyboardAccessoryModernView mMockView;
 
     private final KeyboardAccessoryData.Tab mTestTab =
             new KeyboardAccessoryData.Tab(null, null, 0, 0, null);
@@ -69,6 +72,9 @@
     public void setUp() {
         ShadowRecordHistogram.reset();
         MockitoAnnotations.initMocks(this);
+        HashMap<String, Boolean> features = new HashMap<>();
+        features.put(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY, true);
+        ChromeFeatureList.setTestFeatures(features);
 
         mCoordinator = new KeyboardAccessoryCoordinator(
                 mMockVisibilityDelegate, new FakeViewProvider<>(mMockView));
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
index bdb5aa5..0a219828 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
@@ -17,12 +17,9 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryAction
-        .GENERATE_PASSWORD_AUTOMATIC;
-import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties
-        .ACTIVE_TAB;
-import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties
-        .TABS;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryAction.GENERATE_PASSWORD_AUTOMATIC;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.ACTIVE_TAB;
+import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.TABS;
 import static org.chromium.chrome.browser.tab.Tab.INVALID_TAB_ID;
 import static org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType.FROM_BROWSER_ACTIONS;
 import static org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType.FROM_CLOSE;
@@ -50,8 +47,7 @@
 import org.chromium.chrome.browser.ChromeWindow;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Action;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item;
-import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData
-        .PropertyProvider;
+import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.PropertyProvider;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Provider;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.modelutil.ListModel;
@@ -76,7 +72,8 @@
  */
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE, shadows = {ShadowRecordHistogram.class})
-@EnableFeatures(ChromeFeatureList.PASSWORDS_KEYBOARD_ACCESSORY)
+@EnableFeatures({ChromeFeatureList.PASSWORDS_KEYBOARD_ACCESSORY,
+        ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY})
 @DisableFeatures(ChromeFeatureList.EXPERIMENTAL_UI)
 public class ManualFillingControllerTest {
     @Mock
@@ -88,7 +85,7 @@
     @Mock
     private ViewGroup mMockContentView;
     @Mock
-    private KeyboardAccessoryView mMockKeyboardAccessoryView;
+    private KeyboardAccessoryModernView mMockKeyboardAccessoryView;
     @Mock
     private AccessorySheetView mMockViewPager;
     @Mock
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/FetchHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/FetchHelperTest.java
index 5821906..e8a87a2 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/FetchHelperTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/FetchHelperTest.java
@@ -188,19 +188,20 @@
 
     @Test
     public void tabObserver_onPageLoadFinished() {
-        delayFetchExecutionTest((tabObserver) -> tabObserver.onPageLoadFinished(mTab));
+        delayFetchExecutionTest(
+                (tabObserver) -> tabObserver.onPageLoadFinished(mTab, STARTING_URL));
     }
 
     @Test
     public void tabObserver_onPageLoadFinished_pageLoadStarted_toSame() {
         delayFetchExecutionTest_pageLoadStarted_toSame(
-                (tabObserver) -> tabObserver.onPageLoadFinished(mTab));
+                (tabObserver) -> tabObserver.onPageLoadFinished(mTab, STARTING_URL));
     }
 
     @Test
     public void tabObserver_onPageLoadFinished_pageLoadStarted_toDifferent() {
         delayFetchExecutionTest_pageLoadStarted_toDifferent(
-                (tabObserver) -> tabObserver.onPageLoadFinished(mTab));
+                (tabObserver) -> tabObserver.onPageLoadFinished(mTab, STARTING_URL));
     }
 
     @Test
@@ -224,7 +225,7 @@
     public void tabObserver_multipleSignals_triggersOnce() {
         delayFetchExecutionTest((tabObserver) -> {
             tabObserver.didFirstVisuallyNonEmptyPaint(mTab);
-            tabObserver.onPageLoadFinished(mTab);
+            tabObserver.onPageLoadFinished(mTab, STARTING_URL);
             tabObserver.onLoadStopped(mTab, false);
         });
     }
@@ -367,7 +368,7 @@
         addTab(mTab2);
 
         // First tab finishes load in the background.
-        getTabObserver().onPageLoadFinished(mTab);
+        getTabObserver().onPageLoadFinished(mTab, STARTING_URL);
         verify(mDelegate, times(1)).reportFetchDelayed(eq(mWebContents));
 
         // Switching tabs, therefore the pending fetch is on a background tab.
@@ -404,7 +405,7 @@
                 .getCanonicalUrlForSharing(any());
         FetchHelper helper = createFetchHelper();
 
-        getTabObserver().onPageLoadFinished(mTab);
+        getTabObserver().onPageLoadFinished(mTab, STARTING_URL);
         verify(mFrameHost, times(0)).getCanonicalUrlForSharing(any());
         runUntilFetchPossible();
         verify(mFrameHost, times(1)).getCanonicalUrlForSharing(any());
@@ -432,7 +433,7 @@
         })
                 .when(mFrameHost)
                 .getCanonicalUrlForSharing(any());
-        getTabObserver().onPageLoadFinished(mTab);
+        getTabObserver().onPageLoadFinished(mTab, STARTING_URL);
         runUntilFetchPossible();
         verify(mDelegate, times(0)).requestSuggestions(DIFFERENT_URL);
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/PageViewTimerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/PageViewTimerTest.java
index 72ac00a..ede1cf3 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/PageViewTimerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/PageViewTimerTest.java
@@ -321,7 +321,7 @@
         return () -> getTabObserver().didFirstVisuallyNonEmptyPaint(tab);
     }
     private Runnable showContentByOnPageLoadFinished(Tab tab) {
-        return () -> getTabObserver().onPageLoadFinished(tab);
+        return () -> getTabObserver().onPageLoadFinished(tab, STARTING_URL);
     }
 
     private Runnable showContentByOnLoadStopped(Tab tab) {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java
index 2c89702f..127acab 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java
@@ -45,6 +45,7 @@
 public class OfflinePageTabObserverTest {
     // Using a null tab, as it cannot be mocked. TabHelper will help return proper mocked responses.
     private static final int TAB_ID = 77;
+    private static final String TAB_URL = "mock.com";
 
     @Mock
     private ChromeActivity mActivity;
@@ -76,6 +77,7 @@
         // Setting up a mock tab. These are the values common to most tests, but individual
         // tests might easily overwrite them.
         doReturn(TAB_ID).when(mTab).getId();
+        doReturn(TAB_URL).when(mTab).getUrl();
         doReturn(false).when(mTab).isFrozen();
         doReturn(false).when(mTab).isHidden();
         doReturn(mActivity).when(mTab).getActivity();
@@ -183,7 +185,7 @@
 
         observer.startObservingTab(mTab);
         doReturn(true).when(mOfflinePageUtils).isConnected();
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
 
         verify(observer, times(1)).showReloadSnackbar(any(Tab.class));
     }
@@ -200,7 +202,7 @@
 
         verify(observer, times(0)).showReloadSnackbar(any(Tab.class));
         assertFalse(observer.wasSnackbarSeen(mTab));
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
 
         verify(observer, times(1)).showReloadSnackbar(any(Tab.class));
         assertTrue(observer.isObservingTab(mTab));
@@ -222,7 +224,7 @@
         observer.onUrlUpdated(mTab);
         assertFalse(observer.isLoadedTab(mTab));
 
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
         assertTrue(observer.isLoadedTab(mTab));
 
         verify(observer, times(0)).showReloadSnackbar(any(Tab.class));
@@ -242,7 +244,7 @@
         observer.onUrlUpdated(mTab);
         assertFalse(observer.isLoadedTab(mTab));
 
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
         assertTrue(observer.isLoadedTab(mTab));
 
         verify(observer, times(0)).showReloadSnackbar(any(Tab.class));
@@ -257,7 +259,7 @@
         hideTab(null);
 
         observer.startObservingTab(mTab);
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
 
         verify(observer, times(0)).showReloadSnackbar(any(Tab.class));
         assertFalse(observer.wasSnackbarSeen(mTab));
@@ -279,7 +281,7 @@
 
         observer.startObservingTab(mTab);
         doReturn(true).when(mOfflinePageUtils).isShowingOfflinePreview(mTab);
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
 
         verify(observer, times(0)).showReloadSnackbar(any(Tab.class));
         assertFalse(observer.wasSnackbarSeen(mTab));
@@ -300,7 +302,7 @@
         hideTab(null);
 
         observer.startObservingTab(mTab);
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
 
         observer.onShown(mTab, FROM_NEW);
         verify(observer, times(0)).showReloadSnackbar(any(Tab.class));
@@ -328,7 +330,7 @@
         connect(observer, false);
         showTab(null);
         observer.startObservingTab(mTab);
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
 
         // Snackbar is showing over here.
         verify(observer, times(1)).showReloadSnackbar(any(Tab.class));
@@ -377,7 +379,7 @@
         showTab(null);
 
         observer.startObservingTab(mTab);
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
 
         // Snackbar was shown, so all other conditions are met.
         verify(observer, times(1)).showReloadSnackbar(any(Tab.class));
@@ -429,7 +431,7 @@
         connect(observer, false);
         showTab(null);
         observer.startObservingTab(mTab);
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
 
         // URL updated, but tab still shows offline page.
         observer.onUrlUpdated(mTab);
@@ -440,7 +442,7 @@
         verify(observer, times(0)).stopObservingTab(any(Tab.class));
         verify(mSnackbarManager, times(1)).dismissSnackbars(eq(mSnackbarController));
 
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
 
         // URL updated and tab no longer shows offline page.
         doReturn(false).when(mOfflinePageUtils).isOfflinePage(any(Tab.class));
@@ -497,7 +499,7 @@
         disconnect(observer, false);
         showTab(null);
         observer.startObservingTab(mTab);
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
 
         assertTrue(observer.isObservingNetworkChanges());
 
@@ -514,7 +516,7 @@
         disconnect(observer, false);
         showTab(null);
         observer.startObservingTab(mTab);
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
 
         assertTrue(observer.isObservingNetworkChanges());
 
@@ -533,7 +535,7 @@
         disconnect(observer, false);
         hideTab(null);
         observer.startObservingTab(mTab);
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
 
         assertTrue(observer.isObservingNetworkChanges());
         connect(observer, true);
@@ -587,12 +589,12 @@
         connect(observer, false);
         showTab(null);
         observer.startObservingTab(mTab);
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
 
         verify(observer, times(1)).showReloadSnackbar(any(Tab.class));
 
         // Event ignored, snackbar not shown again.
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
         verify(observer, times(1)).showReloadSnackbar(any(Tab.class));
 
         // Event ignored, snackbar not shown again.
@@ -637,7 +639,7 @@
         connect(observer, false);
         showTab(null);
         observer.startObservingTab(mTab);
-        observer.onPageLoadFinished(mTab);
+        observer.onPageLoadFinished(mTab, TAB_URL);
 
         // Snackbar is showing over here.
         verify(observer, times(1)).showReloadSnackbar(any(Tab.class));
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index fed24db..96f07ea 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -752,6 +752,9 @@
   <message name="IDS_SETTINGS_CREDIT_CARD_EXPIRED" desc="The error message that is shown when user attempts to enter or save an expired card.">
     Your card is expired
   </message>
+  <message name="IDS_SETTINGS_PAYMENTS_PAGE_PRIVACY_LINK_TEXT" desc="The link text of the cross-link to the privacy settings page.">
+    To save payment methods to this device only, add them on this page, or visit <ph name="BEGIN_LINK_CHROMIUM">&lt;a target="_blank" href="$1"&gt;</ph>Privacy &amp; Security settings<ph name="END_LINK_CHROMIUM">&lt;/a&gt;</ph> and turn off the setting "Allow Chrome sign-in"
+  </message>
   <message name="IDS_SETTINGS_PASSWORDS" desc="Name for the password section and toggle">
     Manage passwords
   </message>
diff --git a/chrome/app/vector_icons/resize_handle.icon b/chrome/app/vector_icons/resize_handle.icon
index 3865d96..17f6cc8 100644
--- a/chrome/app/vector_icons/resize_handle.icon
+++ b/chrome/app/vector_icons/resize_handle.icon
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-CANVAS_DIMENSIONS, 15,
+CANVAS_DIMENSIONS, 21,
 STROKE, 2.f,
-MOVE_TO, 2, 2,
+MOVE_TO, 5, 5,
 R_LINE_TO, 11.31f, 11.31f,
-MOVE_TO, 9, 2,
+MOVE_TO, 12, 5,
 R_LINE_TO, 4.24f, 4.24f,
 CLOSE
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 69f0aea..9dc3120 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -50,7 +50,6 @@
 #include "components/autofill/core/common/autofill_switches.h"
 #include "components/autofill/core/common/autofill_util.h"
 #include "components/browser_sync/browser_sync_switches.h"
-#include "components/browsing_data/core/features.h"
 #include "components/cloud_devices/common/cloud_devices_switches.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
@@ -2332,9 +2331,10 @@
     {"autofill-keyboard-accessory-view",
      flag_descriptions::kAutofillAccessoryViewName,
      flag_descriptions::kAutofillAccessoryViewDescription, kOsAndroid,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(autofill::kAutofillKeyboardAccessory,
-                                    kAutofillKeyboardAccessoryFeatureVariations,
-                                    "AutofillKeyboardAccessoryVariations")},
+     FEATURE_WITH_PARAMS_VALUE_TYPE(
+         autofill::features::kAutofillKeyboardAccessory,
+         kAutofillKeyboardAccessoryFeatureVariations,
+         "AutofillKeyboardAccessoryVariations")},
 #endif  // OS_ANDROID
 #if defined(OS_WIN)
     {"try-supported-channel-layouts",
@@ -2806,10 +2806,6 @@
      flag_descriptions::kFullscreenToolbarRevealDescription, kOsMac,
      FEATURE_VALUE_TYPE(features::kFullscreenToolbarReveal)},
 #endif  // OS_MACOSX
-    {"remove-navigation-history",
-     flag_descriptions::kRemoveNavigationHistoryName,
-     flag_descriptions::kRemoveNavigationHistoryDescription, kOsAll,
-     FEATURE_VALUE_TYPE(browsing_data::features::kRemoveNavigationHistory)},
     {"rewrite-leveldb-on-deletion",
      flag_descriptions::kRewriteLevelDBOnDeletionName,
      flag_descriptions::kRewriteLevelDBOnDeletionDescription, kOsAll,
@@ -4069,9 +4065,6 @@
      flag_descriptions::kEnableSyncUserConsentSeparateTypeName,
      flag_descriptions::kEnableSyncUserConsentSeparateTypeDescription, kOsAll,
      FEATURE_VALUE_TYPE(switches::kSyncUserConsentSeparateType)},
-    {"enable-sync-uss-sessions", flag_descriptions::kEnableSyncUSSSessionsName,
-     flag_descriptions::kEnableSyncUSSSessionsDescription, kOsAll,
-     FEATURE_VALUE_TYPE(switches::kSyncUSSSessions)},
     {"enable-experimental-productivity-features",
      flag_descriptions::kExperimentalProductivityFeaturesName,
      flag_descriptions::kExperimentalProductivityFeaturesDescription, kOsAll,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index a4091daf..01e6e4f1 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -49,6 +49,7 @@
 // this array may either refer to features defined in the header of this file or
 // in other locations in the code base (e.g. chrome/, components/, etc).
 const base::Feature* kFeaturesExposedToJava[] = {
+    &autofill::features::kAutofillKeyboardAccessory,
     &autofill::features::kAutofillManualFallbackAndroid,
     &autofill::features::kAutofillRefreshStyleAndroid,
     &autofill::features::kAutofillEnableCompanyName,
diff --git a/chrome/browser/android/customtabs/detached_resource_request.cc b/chrome/browser/android/customtabs/detached_resource_request.cc
index 56839fb..282751f 100644
--- a/chrome/browser/android/customtabs/detached_resource_request.cc
+++ b/chrome/browser/android/customtabs/detached_resource_request.cc
@@ -24,12 +24,6 @@
 
 namespace customtabs {
 
-namespace {
-
-constexpr int kMaxResponseSize = 100 * 1024;
-
-}  // namespace
-
 // static
 void DetachedResourceRequest::CreateAndStart(
     content::BrowserContext* browser_context,
diff --git a/chrome/browser/android/customtabs/detached_resource_request.h b/chrome/browser/android/customtabs/detached_resource_request.h
index 0ad15e8..662bddc 100644
--- a/chrome/browser/android/customtabs/detached_resource_request.h
+++ b/chrome/browser/android/customtabs/detached_resource_request.h
@@ -39,6 +39,8 @@
 // This is a UI thread class.
 class DetachedResourceRequest {
  public:
+  static constexpr int kMaxResponseSize = 100 * 1024;
+
   // The motivation of the resource request, used for histograms reporting.
   // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.customtabs
   // GENERATED_JAVA_CLASS_NAME_OVERRIDE: DetachedResourceRequestMotivation
diff --git a/chrome/browser/android/customtabs/detached_resource_request_unittest.cc b/chrome/browser/android/customtabs/detached_resource_request_unittest.cc
index 8cd628d0..d2542f7 100644
--- a/chrome/browser/android/customtabs/detached_resource_request_unittest.cc
+++ b/chrome/browser/android/customtabs/detached_resource_request_unittest.cc
@@ -39,6 +39,9 @@
 constexpr const char kEchoTitle[] = "/echotitle";
 constexpr const char kManyRedirects[] = "/many-redirects";
 constexpr const char kCacheable[] = "/cachetime";
+constexpr const char kLargeHeadersAndResponseSize[] =
+    "/large-headers-and-response-size";
+
 constexpr const char kCookieKey[] = "cookie";
 constexpr const char kUrlKey[] = "url";
 constexpr const char kCookieFromNoContent[] = "no-content-cookie";
@@ -126,6 +129,26 @@
   return response;
 }
 
+// /large-headers-and-response-size?10000
+// Replies with large headers and a set response body size.
+std::unique_ptr<HttpResponse> LargeHeadersAndResponseSize(
+    const HttpRequest& request) {
+  const GURL& url = request.GetURL();
+  if (url.path() != kLargeHeadersAndResponseSize)
+    return nullptr;
+
+  auto response = std::make_unique<net::test_server::BasicHttpResponse>();
+  response->AddCustomHeader(
+      "X-Large-Header",
+      std::string(DetachedResourceRequest::kMaxResponseSize, 'b'));
+  response->set_code(net::HTTP_OK);
+
+  uint32_t length;
+  CHECK(base::StringToUint(request.GetURL().query(), &length));
+  response->set_content(std::string(length, 'a'));
+  return response;
+}
+
 // Waits for |expected_requests| requests to |path|, then reports the headers
 // in |headers| and calls |closure|.
 // Output parameters can be nullptr.
@@ -160,6 +183,8 @@
         base::BindRepeating(&SetCookieAndNoContent));
     embedded_test_server()->RegisterRequestHandler(
         base::BindRepeating(&ManyRedirects));
+    embedded_test_server()->RegisterRequestHandler(
+        base::BindRepeating(&LargeHeadersAndResponseSize));
     embedded_test_server()->AddDefaultHandlers(
         base::FilePath("chrome/test/data"));
     host_resolver_ = std::make_unique<content::TestHostResolver>();
@@ -298,6 +323,60 @@
       "CustomTabs.DetachedResourceRequest.FinalStatus", -net::ERR_FAILED, 1);
 }
 
+TEST_F(DetachedResourceRequestTest, ResponseTooLarge) {
+  base::HistogramTester histogram_tester;
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL site_for_cookies(embedded_test_server()->base_url());
+
+  // Checks that headers are not included in the size limit (response size is
+  // 1 below the limit, hence above including headers.)
+  {
+    base::RunLoop request_waiter;
+    GURL url(embedded_test_server()->GetURL(
+        base::StringPrintf("%s?%u", kLargeHeadersAndResponseSize,
+                           DetachedResourceRequest::kMaxResponseSize - 1)));
+
+    DetachedResourceRequest::CreateAndStart(
+        browser_context(), url, site_for_cookies,
+        content::Referrer::GetDefaultReferrerPolicy(), kMotivation,
+        base::BindLambdaForTesting([&](int net_error) {
+          EXPECT_EQ(net::OK, net_error);
+          request_waiter.Quit();
+        }));
+    request_waiter.Run();
+    histogram_tester.ExpectUniqueSample(
+        "CustomTabs.DetachedResourceRequest.RedirectsCount.Success", 0, 1);
+    histogram_tester.ExpectTotalCount(
+        "CustomTabs.DetachedResourceRequest.Duration.Success", 1);
+    histogram_tester.ExpectBucketCount(
+        "CustomTabs.DetachedResourceRequest.FinalStatus", net::OK, 1);
+  }
+
+  // Response too large, failure.
+  {
+    base::RunLoop request_waiter;
+    GURL url(embedded_test_server()->GetURL(
+        base::StringPrintf("%s?%u", kLargeHeadersAndResponseSize,
+                           DetachedResourceRequest::kMaxResponseSize + 1)));
+
+    DetachedResourceRequest::CreateAndStart(
+        browser_context(), url, site_for_cookies,
+        content::Referrer::GetDefaultReferrerPolicy(), kMotivation,
+        base::BindLambdaForTesting([&](int net_error) {
+          EXPECT_NE(net::OK, net_error);
+          request_waiter.Quit();
+        }));
+    request_waiter.Run();
+    histogram_tester.ExpectUniqueSample(
+        "CustomTabs.DetachedResourceRequest.RedirectsCount.Failure", 0, 1);
+    histogram_tester.ExpectTotalCount(
+        "CustomTabs.DetachedResourceRequest.Duration.Failure", 1);
+    histogram_tester.ExpectBucketCount(
+        "CustomTabs.DetachedResourceRequest.FinalStatus",
+        -net::ERR_INSUFFICIENT_RESOURCES, 1);
+  }
+}
+
 TEST_F(DetachedResourceRequestTest, MultipleRequests) {
   base::RunLoop request_waiter;
   int expected_requests = 2;
diff --git a/chrome/browser/android/preferences/preferences_launcher.cc b/chrome/browser/android/preferences/preferences_launcher.cc
index 13d9765..f3268bc 100644
--- a/chrome/browser/android/preferences/preferences_launcher.cc
+++ b/chrome/browser/android/preferences/preferences_launcher.cc
@@ -24,9 +24,10 @@
       base::android::AttachCurrentThread(), web_contents->GetJavaWebContents());
 }
 
-void PreferencesLauncher::ShowPasswordSettings() {
+void PreferencesLauncher::ShowPasswordSettings(
+    content::WebContents* web_contents) {
   Java_PreferencesLauncher_showPasswordSettings(
-      base::android::AttachCurrentThread());
+      base::android::AttachCurrentThread(), web_contents->GetJavaWebContents());
 }
 
 }  // namespace android
diff --git a/chrome/browser/android/preferences/preferences_launcher.h b/chrome/browser/android/preferences/preferences_launcher.h
index ff51f764..f1412c6 100644
--- a/chrome/browser/android/preferences/preferences_launcher.h
+++ b/chrome/browser/android/preferences/preferences_launcher.h
@@ -24,7 +24,7 @@
       content::WebContents* web_contents);
 
   // Opens the password settings page.
-  static void ShowPasswordSettings();
+  static void ShowPasswordSettings(content::WebContents* web_contents);
 
  private:
   PreferencesLauncher() {}
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 1c2a2df..54337242 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -1113,17 +1113,16 @@
 }
 
 // This test exercises the webview spatial navigation API
-// This test is disabled due to being flaky. http://crbug.com/884306
-IN_PROC_BROWSER_TEST_F(WebViewTest, DISABLED_SpatialNavigationJavascriptAPI) {
+IN_PROC_BROWSER_TEST_F(WebViewTest, SpatialNavigationJavascriptAPI) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableSpatialNavigation);
 
-  LoadAndLaunchPlatformApp("web_view/spatial_navigation_state_api",
-                           "WebViewTest.LAUNCHED");
-
   ExtensionTestMessageListener next_step_listener("TEST_STEP_PASSED", false);
   next_step_listener.set_failure_message("TEST_STEP_FAILED");
 
+  LoadAndLaunchPlatformApp("web_view/spatial_navigation_state_api",
+                           "WebViewTest.LAUNCHED");
+
   // Check that spatial navigation is initialized in the beginning
   ASSERT_TRUE(next_step_listener.WaitUntilSatisfied());
   next_step_listener.Reset();
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
index 90ea888..b359210 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
@@ -251,7 +251,8 @@
     const std::string& method,
     const GURL& url,
     const net::NetworkTrafficAnnotationTag& traffic_annotation,
-    const net::HttpRequestHeaders& headers) {
+    const net::HttpRequestHeaders& headers,
+    bool has_request_body) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(job_details_map_.count(job_unique_id));
   DCHECK(!download_job_unique_id_map_.count(download_guid));
@@ -283,9 +284,9 @@
   if (job_details.job_state == JobDetails::State::kStartedButPaused) {
     job_details.on_resume =
         base::BindOnce(&BackgroundFetchDelegateImpl::StartDownload,
-                       GetWeakPtr(), job_unique_id, params);
+                       GetWeakPtr(), job_unique_id, params, has_request_body);
   } else {
-    StartDownload(job_unique_id, params);
+    StartDownload(job_unique_id, params, has_request_body);
   }
 
   UpdateOfflineItemAndUpdateObservers(&job_details);
@@ -293,10 +294,13 @@
 
 void BackgroundFetchDelegateImpl::StartDownload(
     const std::string& job_unique_id,
-    const download::DownloadParams& params) {
+    const download::DownloadParams& params,
+    bool has_request_body) {
   DCHECK(job_details_map_.count(job_unique_id));
   JobDetails& job_details = job_details_map_.find(job_unique_id)->second;
-  job_details.current_download_guids.insert(params.guid);
+  job_details.current_fetch_guids.emplace(
+      params.guid, has_request_body ? JobDetails::UploadData::kIncluded
+                                    : JobDetails::UploadData::kAbsent);
   GetDownloadService()->StartDownload(params);
 }
 
@@ -310,9 +314,9 @@
   JobDetails& job_details = job_details_iter->second;
   job_details.job_state = JobDetails::State::kCancelled;
 
-  for (const auto& download_guid : job_details.current_download_guids) {
-    GetDownloadService()->CancelDownload(download_guid);
-    download_job_unique_id_map_.erase(download_guid);
+  for (const auto& download_guid_pair : job_details.current_fetch_guids) {
+    GetDownloadService()->CancelDownload(download_guid_pair.first);
+    download_job_unique_id_map_.erase(download_guid_pair.first);
   }
   UpdateOfflineItemAndUpdateObservers(&job_details);
 }
@@ -429,7 +433,7 @@
                                  std::move(result));
   }
 
-  job_details.current_download_guids.erase(download_guid);
+  job_details.current_fetch_guids.erase(download_guid);
   download_job_unique_id_map_.erase(download_guid);
 }
 
@@ -459,8 +463,7 @@
                                  std::move(result));
   }
 
-  job_details.current_download_guids.erase(
-      job_details.current_download_guids.find(download_guid));
+  job_details.current_fetch_guids.erase(download_guid);
   download_job_unique_id_map_.erase(download_guid);
 }
 
@@ -557,8 +560,8 @@
   JobDetails& job_details = job_details_iter->second;
   job_details.job_state = JobDetails::State::kStartedButPaused;
   job_details.UpdateOfflineItem();
-  for (auto& download_guid : job_details.current_download_guids)
-    GetDownloadService()->PauseDownload(download_guid);
+  for (auto& download_guid_pair : job_details.current_fetch_guids)
+    GetDownloadService()->PauseDownload(download_guid_pair.first);
 }
 
 void BackgroundFetchDelegateImpl::ResumeDownload(
@@ -571,8 +574,8 @@
   JobDetails& job_details = job_details_iter->second;
   job_details.job_state = JobDetails::State::kStartedAndDownloading;
   job_details.UpdateOfflineItem();
-  for (auto& download_guid : job_details.current_download_guids)
-    GetDownloadService()->ResumeDownload(download_guid);
+  for (auto& download_guid_pair : job_details.current_fetch_guids)
+    GetDownloadService()->ResumeDownload(download_guid_pair.first);
 
   if (job_details.on_resume)
     std::move(job_details.on_resume).Run();
@@ -683,3 +686,22 @@
   }
   return outstanding_guids;
 }
+
+void BackgroundFetchDelegateImpl::GetUploadData(
+    const std::string& download_guid,
+    download::GetUploadDataCallback callback) {
+  auto job_it = download_job_unique_id_map_.find(download_guid);
+  DCHECK(job_it != download_job_unique_id_map_.end());
+
+  JobDetails& job_details = job_details_map_.find(job_it->second)->second;
+  if (job_details.current_fetch_guids[download_guid] ==
+      JobDetails::UploadData::kAbsent) {
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(std::move(callback), /* request_body= */ nullptr));
+    return;
+  }
+
+  if (client())
+    client()->GetUploadData(job_it->second, download_guid, std::move(callback));
+}
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.h b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
index e355a1f8..65f797d 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.h
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
@@ -63,7 +63,8 @@
                    const std::string& method,
                    const GURL& url,
                    const net::NetworkTrafficAnnotationTag& traffic_annotation,
-                   const net::HttpRequestHeaders& headers) override;
+                   const net::HttpRequestHeaders& headers,
+                   bool has_request_body) override;
   void Abort(const std::string& job_unique_id) override;
   void MarkJobComplete(const std::string& job_unique_id) override;
   void UpdateUI(const std::string& job_unique_id,
@@ -118,6 +119,10 @@
   // GUIDs.
   std::set<std::string> TakeOutstandingGuids();
 
+  // Gets the upload data, if any, associated with the |download_guid|.
+  void GetUploadData(const std::string& download_guid,
+                     download::GetUploadDataCallback callback);
+
   base::WeakPtr<BackgroundFetchDelegateImpl> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
   }
@@ -147,10 +152,15 @@
     void UpdateOfflineItem();
     void MarkJobAsStarted();
 
-    // Set of DownloadService GUIDs that are currently downloading. They are
-    // added by DownloadUrl and are removed when the download completes, fails
-    // or is cancelled.
-    base::flat_set<std::string> current_download_guids;
+    enum class UploadData {
+      kAbsent,
+      kIncluded,
+    };
+
+    // Set of DownloadService GUIDs that are currently processed. They are
+    // added by DownloadUrl and are removed when the fetch completes, fails,
+    // or is cancelled. The GUID maps to whether the fetch has upload data.
+    std::map<std::string, UploadData> current_fetch_guids;
 
     offline_items_collection::OfflineItem offline_item;
     State job_state;
@@ -168,7 +178,8 @@
 
   // Starts a download according to |params| belonging to |job_unique_id|.
   void StartDownload(const std::string& job_unique_id,
-                     const download::DownloadParams& params);
+                     const download::DownloadParams& params,
+                     bool has_request_body);
 
   // Updates the OfflineItem that controls the contents of download
   // notifications and notifies any OfflineContentProvider::Observer that was
diff --git a/chrome/browser/background_fetch/background_fetch_download_client.cc b/chrome/browser/background_fetch/background_fetch_download_client.cc
index 27cbf6d1..d11b1bb 100644
--- a/chrome/browser/background_fetch/background_fetch_download_client.cc
+++ b/chrome/browser/background_fetch/background_fetch_download_client.cc
@@ -147,8 +147,7 @@
 void BackgroundFetchDownloadClient::GetUploadData(
     const std::string& guid,
     download::GetUploadDataCallback callback) {
-  base::SequencedTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), nullptr));
+  GetDelegate()->GetUploadData(guid, std::move(callback));
 }
 
 BackgroundFetchDelegateImpl* BackgroundFetchDownloadClient::GetDelegate() {
diff --git a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
index ef59e45..b16c80a 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
@@ -1103,7 +1103,6 @@
     // TODO(crbug.com/823071): LevelDB logs are not deleted immediately.
     "File System/Origins/[0-9]*.log",
     "Service Worker/Database/[0-9]*.log",
-    "Session Storage/[0-9]*.log",
 
 #if defined(OS_CHROMEOS)
     // TODO(crbug.com/846297): Many leveldb files remain on ChromeOS. I couldn't
diff --git a/chrome/browser/browsing_data/counters/sync_aware_counter_browsertest.cc b/chrome/browser/browsing_data/counters/sync_aware_counter_browsertest.cc
index de2328f..00373a9 100644
--- a/chrome/browser/browsing_data/counters/sync_aware_counter_browsertest.cc
+++ b/chrome/browser/browsing_data/counters/sync_aware_counter_browsertest.cc
@@ -138,9 +138,10 @@
       syncer::UserSelectableTypes();
   everything_except_autofill.Remove(syncer::AUTOFILL);
   auto sync_blocker = sync_service->GetSetupInProgressHandle();
-  sync_service->OnUserChoseDatatypes(/*sync_everything=*/false,
-                                     everything_except_autofill);
-  ASSERT_FALSE(sync_service->GetPreferredDataTypes().Has(syncer::AUTOFILL));
+  sync_service->GetUserSettings()->SetChosenDataTypes(
+      /*sync_everything=*/false, everything_except_autofill);
+  ASSERT_FALSE(sync_service->GetUserSettings()->GetChosenDataTypes().Has(
+      syncer::AUTOFILL));
   sync_blocker.reset();
   WaitForCounting();
   ASSERT_FALSE(sync_service->GetActiveDataTypes().Has(syncer::AUTOFILL));
@@ -149,20 +150,21 @@
   // If autofill sync is not affected, the counter is not restarted.
   syncer::ModelTypeSet only_history(syncer::TYPED_URLS);
   sync_blocker = sync_service->GetSetupInProgressHandle();
-  sync_service->OnUserChoseDatatypes(/*sync_everything=*/false, only_history);
+  sync_service->GetUserSettings()->SetChosenDataTypes(/*sync_everything=*/false,
+                                                      only_history);
   sync_blocker.reset();
   EXPECT_FALSE(CountingFinishedSinceLastAsked());
 
   // We start syncing autofill again. This restarts the counter.
   sync_blocker = sync_service->GetSetupInProgressHandle();
-  sync_service->OnUserChoseDatatypes(/*sync_everything=*/false,
-                                     syncer::UserSelectableTypes());
+  sync_service->GetUserSettings()->SetChosenDataTypes(
+      /*sync_everything=*/false, syncer::UserSelectableTypes());
   sync_blocker.reset();
   WaitForCounting();
   EXPECT_TRUE(IsSyncEnabled());
 
   // Stopping the Sync service triggers a restart.
-  sync_service->RequestStop(syncer::SyncService::CLEAR_DATA);
+  sync_service->GetUserSettings()->SetSyncRequested(false);
   WaitForCounting();
   EXPECT_FALSE(IsSyncEnabled());
 }
@@ -191,7 +193,8 @@
   // syncing passwords, and this should restart the counter.
   ASSERT_TRUE(SetupSync());
   ASSERT_TRUE(sync_service->IsSyncFeatureActive());
-  ASSERT_TRUE(sync_service->GetPreferredDataTypes().Has(syncer::PASSWORDS));
+  ASSERT_TRUE(sync_service->GetUserSettings()->GetChosenDataTypes().Has(
+      syncer::PASSWORDS));
   WaitForCounting();
   EXPECT_TRUE(IsSyncEnabled());
 
@@ -206,7 +209,8 @@
         GetClient(kFirstProfileIndex)
             ->AwaitSyncSetupCompletion(/*skip_passphrase_verification=*/false));
     WaitForCounting();
-    ASSERT_TRUE(sync_service->GetPreferredDataTypes().Has(syncer::PASSWORDS));
+    ASSERT_TRUE(sync_service->GetUserSettings()->GetChosenDataTypes().Has(
+        syncer::PASSWORDS));
   }
 
   // We stop syncing passwords in particular. This restarts the counter.
@@ -214,32 +218,36 @@
       syncer::UserSelectableTypes();
   everything_except_passwords.Remove(syncer::PASSWORDS);
   auto sync_blocker = sync_service->GetSetupInProgressHandle();
-  sync_service->OnUserChoseDatatypes(/*sync_everything=*/false,
-                                     everything_except_passwords);
-  ASSERT_FALSE(sync_service->GetPreferredDataTypes().Has(syncer::PASSWORDS));
+  sync_service->GetUserSettings()->SetChosenDataTypes(
+      /*sync_everything=*/false, everything_except_passwords);
+  ASSERT_FALSE(sync_service->GetUserSettings()->GetChosenDataTypes().Has(
+      syncer::PASSWORDS));
   sync_blocker.reset();
   WaitForCounting();
-  ASSERT_FALSE(sync_service->GetPreferredDataTypes().Has(syncer::PASSWORDS));
+  ASSERT_FALSE(sync_service->GetUserSettings()->GetChosenDataTypes().Has(
+      syncer::PASSWORDS));
   EXPECT_FALSE(IsSyncEnabled());
 
   // If password sync is not affected, the counter is not restarted.
   syncer::ModelTypeSet only_history(syncer::TYPED_URLS);
-  sync_service->OnUserChoseDatatypes(/*sync_everything=*/false, only_history);
+  sync_service->GetUserSettings()->SetChosenDataTypes(/*sync_everything=*/false,
+                                                      only_history);
   sync_blocker = sync_service->GetSetupInProgressHandle();
-  sync_service->OnUserChoseDatatypes(/*sync_everything=*/false, only_history);
+  sync_service->GetUserSettings()->SetChosenDataTypes(/*sync_everything=*/false,
+                                                      only_history);
   sync_blocker.reset();
   EXPECT_FALSE(CountingFinishedSinceLastAsked());
 
   // We start syncing passwords again. This restarts the counter.
   sync_blocker = sync_service->GetSetupInProgressHandle();
-  sync_service->OnUserChoseDatatypes(/*sync_everything=*/false,
-                                     syncer::UserSelectableTypes());
+  sync_service->GetUserSettings()->SetChosenDataTypes(
+      /*sync_everything=*/false, syncer::UserSelectableTypes());
   sync_blocker.reset();
   WaitForCounting();
   EXPECT_TRUE(IsSyncEnabled());
 
   // Stopping the Sync service triggers a restart.
-  sync_service->RequestStop(syncer::SyncService::CLEAR_DATA);
+  sync_service->GetUserSettings()->SetSyncRequested(false);
   WaitForCounting();
   EXPECT_FALSE(IsSyncEnabled());
 }
@@ -271,8 +279,8 @@
   // syncing history deletion, and this should restart the counter.
   ASSERT_TRUE(SetupSync());
   ASSERT_TRUE(sync_service->IsSyncFeatureActive());
-  ASSERT_TRUE(sync_service->GetPreferredDataTypes().Has(
-      syncer::HISTORY_DELETE_DIRECTIVES));
+  ASSERT_TRUE(sync_service->GetUserSettings()->GetChosenDataTypes().Has(
+      syncer::TYPED_URLS));
   ASSERT_TRUE(sync_service->GetActiveDataTypes().Has(
       syncer::HISTORY_DELETE_DIRECTIVES));
 
@@ -299,17 +307,19 @@
       syncer::UserSelectableTypes();
   everything_except_history.Remove(syncer::TYPED_URLS);
   auto sync_blocker = sync_service->GetSetupInProgressHandle();
-  sync_service->OnUserChoseDatatypes(/*sync_everything=*/false,
-                                     everything_except_history);
+  sync_service->GetUserSettings()->SetChosenDataTypes(
+      /*sync_everything=*/false, everything_except_history);
   sync_blocker.reset();
   WaitForCounting();
   EXPECT_FALSE(IsSyncEnabled());
 
   // If the history deletion sync is not affected, the counter is not restarted.
   syncer::ModelTypeSet only_passwords(syncer::PASSWORDS);
-  sync_service->OnUserChoseDatatypes(/*sync_everything=*/false, only_passwords);
+  sync_service->GetUserSettings()->SetChosenDataTypes(/*sync_everything=*/false,
+                                                      only_passwords);
   sync_blocker = sync_service->GetSetupInProgressHandle();
-  sync_service->OnUserChoseDatatypes(/*sync_everything=*/false, only_passwords);
+  sync_service->GetUserSettings()->SetChosenDataTypes(/*sync_everything=*/false,
+                                                      only_passwords);
   sync_blocker.reset();
   EXPECT_FALSE(counter.HasTrackedTasks());
   EXPECT_FALSE(CountingFinishedSinceLastAsked());
@@ -318,16 +328,16 @@
   syncer::ModelTypeSet autofill_and_passwords(syncer::AUTOFILL,
                                               syncer::PASSWORDS);
   sync_blocker = sync_service->GetSetupInProgressHandle();
-  sync_service->OnUserChoseDatatypes(/*sync_everything=*/false,
-                                     autofill_and_passwords);
+  sync_service->GetUserSettings()->SetChosenDataTypes(/*sync_everything=*/false,
+                                                      autofill_and_passwords);
   sync_blocker.reset();
   EXPECT_FALSE(counter.HasTrackedTasks());
   EXPECT_FALSE(CountingFinishedSinceLastAsked());
 
   // We start syncing history deletion again. This restarts the counter.
   sync_blocker = sync_service->GetSetupInProgressHandle();
-  sync_service->OnUserChoseDatatypes(/*sync_everything=*/false,
-                                     syncer::UserSelectableTypes());
+  sync_service->GetUserSettings()->SetChosenDataTypes(
+      /*sync_everything=*/false, syncer::UserSelectableTypes());
   sync_blocker.reset();
   WaitForCounting();
   EXPECT_TRUE(IsSyncEnabled());
@@ -339,7 +349,7 @@
   // active again.
 
   // Stopping the Sync service triggers a restart.
-  sync_service->RequestStop(syncer::SyncService::CLEAR_DATA);
+  sync_service->GetUserSettings()->SetSyncRequested(false);
   WaitForCounting();
   EXPECT_FALSE(IsSyncEnabled());
 }
diff --git a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager_browsertest.cc b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager_browsertest.cc
index 8de926e..5acaebb 100644
--- a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager_browsertest.cc
+++ b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager_browsertest.cc
@@ -163,6 +163,7 @@
     ASSERT_EQ(app2.display_name(), apps[1]->name());
     EXPECT_FALSE(manager()->GetAutoLaunchAccountId().is_valid());
     EXPECT_FALSE(manager()->current_app_was_auto_launched_with_zero_delay());
+    CleanApps();
   }
 
   // Set auto-launch app.
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
index 5e78f23..d9a554e 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/test/base/testing_profile.h"
@@ -37,7 +36,6 @@
 #include "components/drive/drive_pref_names.h"
 #include "components/drive/file_change.h"
 #include "components/prefs/pref_service.h"
-#include "components/signin/core/browser/signin_manager_base.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/install_warning.h"
 #include "google_apis/drive/test_util.h"
@@ -365,7 +363,6 @@
         {features::kCrostini, features::kExperimentalCrostiniUI}, {});
     // Profile must be signed in with email for crostini.
     identity::SetPrimaryAccount(
-        SigninManagerFactory::GetForProfileIfExists(browser()->profile()),
         IdentityManagerFactory::GetForProfileIfExists(browser()->profile()),
         "testuser@gmail.com");
   }
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index e34a1e1..edce74eb 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -544,19 +544,12 @@
                       TestCase("shareFileDrive").EnableDriveFs(),
                       TestCase("shareDirectoryDrive").DisableDriveFs(),
                       TestCase("shareDirectoryDrive").EnableDriveFs(),
-                      TestCase("shareHostedFileDrive"),
                       TestCase("manageHostedFileDrive").DisableDriveFs(),
                       TestCase("manageHostedFileDrive").EnableDriveFs(),
                       TestCase("manageFileDrive").DisableDriveFs(),
                       TestCase("manageFileDrive").EnableDriveFs(),
                       TestCase("manageDirectoryDrive").DisableDriveFs(),
-                      TestCase("manageDirectoryDrive").EnableDriveFs(),
-                      TestCase("shareFileTeamDrive"),
-                      TestCase("shareDirectoryTeamDrive"),
-                      TestCase("shareHostedFileTeamDrive"),
-                      TestCase("manageHostedFileTeamDrive"),
-                      TestCase("manageFileTeamDrive"),
-                      TestCase("manageDirectoryTeamDrive")));
+                      TestCase("manageDirectoryDrive").EnableDriveFs()));
 
 WRAPPED_INSTANTIATE_TEST_CASE_P(
     SuggestAppDialog, /* suggest_app_dialog.js */
diff --git a/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc b/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc
index dde669c..cef3397 100644
--- a/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc
+++ b/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc
@@ -62,11 +62,14 @@
 
 void StubCrosSettingsProvider::DoSet(const std::string& path,
                                      const base::Value& value) {
+  bool is_value_changed = false;
   if (current_user_is_owner_)
-    values_.SetValue(path, value.CreateDeepCopy());
+    is_value_changed = values_.SetValue(path, value.CreateDeepCopy());
   else
     LOG(WARNING) << "Changing settings from non-owner, setting=" << path;
-  NotifyObservers(path);
+
+  if (is_value_changed || !current_user_is_owner_)
+    NotifyObservers(path);
 }
 
 void StubCrosSettingsProvider::SetDefaults() {
diff --git a/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc b/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc
index 4208518..49d181f5 100644
--- a/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc
+++ b/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc
@@ -264,6 +264,8 @@
                   content::BrowsingDataRemover::DATA_TYPE_APP_CACHE) |
         GetAsMask(data_to_remove, "cache",
                   content::BrowsingDataRemover::DATA_TYPE_CACHE) |
+        GetAsMask(data_to_remove, "cacheStorage",
+                  content::BrowsingDataRemover::DATA_TYPE_CACHE_STORAGE) |
         GetAsMask(data_to_remove, "cookies",
                   content::BrowsingDataRemover::DATA_TYPE_COOKIES) |
         GetAsMask(data_to_remove, "downloads",
@@ -284,8 +286,6 @@
                   ChromeBrowsingDataRemoverDelegate::DATA_TYPE_PASSWORDS) |
         GetAsMask(data_to_remove, "serviceWorkers",
                   content::BrowsingDataRemover::DATA_TYPE_SERVICE_WORKERS) |
-        GetAsMask(data_to_remove, "cacheStorage",
-                  content::BrowsingDataRemover::DATA_TYPE_CACHE_STORAGE) |
         GetAsMask(data_to_remove, "webSQL",
                   content::BrowsingDataRemover::DATA_TYPE_WEB_SQL) |
         GetAsMask(data_to_remove, "serverBoundCertificates",
@@ -353,6 +353,7 @@
 
   CheckRemovalPermitted("{\"appcache\": true}", true);
   CheckRemovalPermitted("{\"cache\": true}", true);
+  CheckRemovalPermitted("{\"cacheStorage\": true}", true);
   CheckRemovalPermitted("{\"cookies\": true}", true);
   CheckRemovalPermitted("{\"downloads\": true}", false);
   CheckRemovalPermitted("{\"fileSystems\": true}", true);
@@ -363,7 +364,6 @@
   CheckRemovalPermitted("{\"serverBoundCertificates\": true}", true);
   CheckRemovalPermitted("{\"passwords\": true}", true);
   CheckRemovalPermitted("{\"serviceWorkers\": true}", true);
-  CheckRemovalPermitted("{\"cacheStorage\": true}", true);
   CheckRemovalPermitted("{\"webSQL\": true}", true);
 
   // The entire removal is prohibited if any part is.
@@ -533,6 +533,8 @@
   RunBrowsingDataRemoveWithKeyAndCompareRemovalMask(
       "cache", content::BrowsingDataRemover::DATA_TYPE_CACHE);
   RunBrowsingDataRemoveWithKeyAndCompareRemovalMask(
+      "cacheStorage", content::BrowsingDataRemover::DATA_TYPE_CACHE_STORAGE);
+  RunBrowsingDataRemoveWithKeyAndCompareRemovalMask(
       "cookies", content::BrowsingDataRemover::DATA_TYPE_COOKIES);
   RunBrowsingDataRemoveWithKeyAndCompareRemovalMask(
       "downloads", content::BrowsingDataRemover::DATA_TYPE_DOWNLOADS);
@@ -556,8 +558,6 @@
       "serviceWorkers",
       content::BrowsingDataRemover::DATA_TYPE_SERVICE_WORKERS);
   RunBrowsingDataRemoveWithKeyAndCompareRemovalMask(
-      "cacheStorage", content::BrowsingDataRemover::DATA_TYPE_CACHE_STORAGE);
-  RunBrowsingDataRemoveWithKeyAndCompareRemovalMask(
       "webSQL", content::BrowsingDataRemover::DATA_TYPE_WEB_SQL);
 }
 
@@ -624,6 +624,8 @@
       content::BrowsingDataRemover::DATA_TYPE_APP_CACHE);
   RunAndCompareRemovalMask<BrowsingDataRemoveCacheFunction>(
       content::BrowsingDataRemover::DATA_TYPE_CACHE);
+  RunAndCompareRemovalMask<BrowsingDataRemoveCacheStorageFunction>(
+      content::BrowsingDataRemover::DATA_TYPE_CACHE_STORAGE);
   RunAndCompareRemovalMask<BrowsingDataRemoveCookiesFunction>(
       content::BrowsingDataRemover::DATA_TYPE_COOKIES |
       content::BrowsingDataRemover::DATA_TYPE_CHANNEL_IDS);
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc
index 2c8f4e2..e6b57bf 100644
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -489,8 +489,7 @@
   std::string SignIn(const std::string& email) {
     identity::IdentityManager* identity_manager =
         IdentityManagerFactory::GetForProfile(profile());
-    identity::MakePrimaryAccountAvailable(signin_manager_, token_service_,
-                                          identity_manager, email);
+    identity::MakePrimaryAccountAvailable(identity_manager, email);
     return identity_manager->GetPrimaryAccountId();
   }
 
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index d146db2a..cb9a35b 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -783,6 +783,17 @@
     const std::string& pref_name,
     const base::Value* value) {
 #if defined(OS_CHROMEOS)
+  if (pref_name == chromeos::kSystemTimezone) {
+    std::string string_value;
+    if (!value->GetAsString(&string_value))
+      return settings_private::SetPrefResult::PREF_TYPE_MISMATCH;
+    const user_manager::User* user =
+        chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+    if (user && chromeos::system::SetSystemTimezone(user, string_value))
+      return settings_private::SetPrefResult::SUCCESS;
+    return settings_private::SetPrefResult::PREF_NOT_MODIFIABLE;
+  }
+
   chromeos::OwnerSettingsServiceChromeOS* service =
       chromeos::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
           profile_);
@@ -794,6 +805,11 @@
     return settings_private::SetPrefResult::PREF_NOT_MODIFIABLE;
   }
 
+  // TODO(olsen): Remove this call, as per http://crbug.com/433840
+  // Note: Since kSystemTimezone (the only system setting) is already handled,
+  // we should only arrive here in two cases (of which one may be a bug):
+  // 1. User is guest, so service=nullptr. Maybe a bug to call Set in this case?
+  // 2. kStubCrosSettings is true, so service->HandlesSetting is false.
   CrosSettings::Get()->Set(pref_name, *value);
   return settings_private::SetPrefResult::SUCCESS;
 #else
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 62eee2d6..71d09b0 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -289,7 +289,7 @@
   },
   {
     "name": "automatic-password-generation",
-    // "owners": [ "your-team" ],
+    "owners": [ "ioanap", "fhorschig" ],
     "expiry_milestone": 76
   },
   {
@@ -344,8 +344,8 @@
   },
   {
     "name": "clear-old-browsing-data",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
+    "owners": [ "dullweber" ],
+    "expiry_milestone": 78
   },
   {
     "name": "click-to-open-pdf",
@@ -448,6 +448,11 @@
     "expiry_milestone": 76
   },
   {
+    "name": "dcheck-is-fatal",
+    // "owners": [ "your-team" ],
+    "expiry_milestone": 76
+  },
+  {
     "name": "debug-packed-apps",
     // "owners": [ "your-team" ],
     "expiry_milestone": 76
@@ -1208,6 +1213,11 @@
     "expiry_milestone": 76
   },
   {
+    "name": "enable-google-branded-context-menu",
+    // "owners": [ "your-team" ],
+    "expiry_milestone": 76
+  },
+  {
     "name": "enable-gpu-appcontainer",
     // "owners": [ "your-team" ],
     "expiry_milestone": 76
@@ -1659,7 +1669,8 @@
   },
   {
     "name": "enable-service-worker-imported-script-update-check",
-    // "owners": [ "your-team" ],
+    "owners": [ "worker-dev@chromium.org" ],
+    // It's still in development. Tentatively set to M76 as the expiry_milestone.
     "expiry_milestone": 76
   },
   {
@@ -1669,8 +1680,9 @@
   },
   {
     "name": "enable-service-worker-servicification",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
+    "owners": [ "worker-dev@chromium.org" ],
+    // Enabled by default in M72.
+    "expiry_milestone": 73
   },
   {
     "name": "enable-settings-shortcut-search",
@@ -2483,6 +2495,11 @@
     "expiry_milestone": 76
   },
   {
+    "name": "oculus-vr",
+    // "owners": [ "your-team" ],
+    "expiry_milestone": 76
+  },
+  {
     "name": "offline-bookmarks",
     // "owners": [ "your-team" ],
     "expiry_milestone": 76
@@ -2719,12 +2736,12 @@
   },
   {
     "name": "password-search",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
+    "owners": [ "fhorschig" ],
+    "expiry_milestone": 73
   },
   {
     "name": "passwords-keyboard-accessory",
-    // "owners": [ "your-team" ],
+    "owners": [ "fhorschig" ],
     "expiry_milestone": 76
   },
   {
@@ -2813,19 +2830,14 @@
     "expiry_milestone": 76
   },
   {
-    "name": "remove-navigation-history",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "reset-app-list-install-state",
     // "owners": [ "your-team" ],
     "expiry_milestone": 76
   },
   {
     "name": "rewrite-leveldb-on-deletion",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
+    "owners": [ "dullweber" ],
+    "expiry_milestone": 75
   },
   {
     "name": "safe-browsing-use-local-blacklists-v2",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 587b6b4..b88761d7 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1606,12 +1606,6 @@
     "user in Language Settings. The actual locale of the system is derived "
     "from the user selection based on some simple fallback logic.";
 
-const char kRemoveNavigationHistoryName[] =
-    "Remove navigation entry on history deletion";
-const char kRemoveNavigationHistoryDescription[] =
-    "Remove a navigation entry when the corresponding history entry has been "
-    "deleted.";
-
 const char kRewriteLevelDBOnDeletionName[] =
     "Rewrite LevelDB instances after full deletions";
 const char kRewriteLevelDBOnDeletionDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index ada6c951..a44138a 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -976,9 +976,6 @@
 extern const char kRegionalLocalesAsDisplayUIName[];
 extern const char kRegionalLocalesAsDisplayUIDescription[];
 
-extern const char kRemoveNavigationHistoryName[];
-extern const char kRemoveNavigationHistoryDescription[];
-
 extern const char kRewriteLevelDBOnDeletionName[];
 extern const char kRewriteLevelDBOnDeletionDescription[];
 
diff --git a/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.cc b/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.cc
index 26a30f27..3a19abcb 100644
--- a/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.cc
+++ b/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.cc
@@ -8,6 +8,8 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/android/android_theme_resources.h"
+#include "chrome/browser/android/preferences/preferences_launcher.h"
+#include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/infobars/core/infobar.h"
 #include "components/infobars/core/infobar_manager.h"
@@ -21,9 +23,8 @@
     ~GeneratedPasswordSavedInfoBarDelegateAndroid() {}
 
 void GeneratedPasswordSavedInfoBarDelegateAndroid::OnInlineLinkClicked() {
-  GURL dashboard_link(l10n_util::GetStringUTF16(IDS_PASSWORDS_WEB_LINK));
-  infobar()->owner()->OpenURL(dashboard_link,
-                              WindowOpenDisposition::NEW_FOREGROUND_TAB);
+  chrome::android::PreferencesLauncher::ShowPasswordSettings(
+      InfoBarService::WebContentsFromInfoBar(infobar()));
 }
 
 GeneratedPasswordSavedInfoBarDelegateAndroid::
@@ -32,8 +33,10 @@
   base::string16 link = l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_LINK);
 
   size_t offset = 0;
-  message_text_ = l10n_util::GetStringFUTF16(
-      IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT_INFOBAR, link, &offset);
+  message_text_ =
+      l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_CONFIRM_SAVED_TITLE);
+  details_message_text_ = l10n_util::GetStringFUTF16(
+      IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TEXT, link, &offset);
   inline_link_range_ = gfx::Range(offset, offset + link.length());
 }
 
diff --git a/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h b/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h
index 34b58d6..f169798 100644
--- a/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h
+++ b/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h
@@ -27,7 +27,12 @@
   // Returns the translated text of the message to display.
   const base::string16& message_text() const { return message_text_; }
 
-  // Returns the range of the message text that should be a link.
+  // Returns the translated text of the details message to display. T
+  const base::string16& details_message_text() const {
+    return details_message_text_;
+  }
+
+  // Returns the range of the details message text that should be a link.
   const gfx::Range& inline_link_range() const { return inline_link_range_; }
 
   // Returns the translated label of the button.
@@ -46,7 +51,11 @@
   // The translated text of the message to display.
   base::string16 message_text_;
 
-  // The range of the message that should be a link.
+  // The translated text of the details message to display. This message
+  // explains where the generated password is saved.
+  base::string16 details_message_text_;
+
+  // The range of the details message that should be a link.
   gfx::Range inline_link_range_;
 
   // The translated label of the button.
diff --git a/chrome/browser/password_manager/password_accessory_controller.cc b/chrome/browser/password_manager/password_accessory_controller.cc
index b84ab6c2..9317a66 100644
--- a/chrome/browser/password_manager/password_accessory_controller.cc
+++ b/chrome/browser/password_manager/password_accessory_controller.cc
@@ -279,7 +279,7 @@
     UMA_HISTOGRAM_ENUMERATION("KeyboardAccessory.AccessoryActionSelected",
                               metrics::AccessoryAction::MANAGE_PASSWORDS,
                               metrics::AccessoryAction::COUNT);
-    chrome::android::PreferencesLauncher::ShowPasswordSettings();
+    chrome::android::PreferencesLauncher::ShowPasswordSettings(web_contents_);
   }
 }
 
diff --git a/chrome/browser/password_manager/password_accessory_metrics_util.h b/chrome/browser/password_manager/password_accessory_metrics_util.h
index 57bb8ed..dd03c90b5 100644
--- a/chrome/browser/password_manager/password_accessory_metrics_util.h
+++ b/chrome/browser/password_manager/password_accessory_metrics_util.h
@@ -57,6 +57,7 @@
   GENERATE_PASSWORD_AUTOMATIC = 0,
   MANAGE_PASSWORDS = 1,
   AUTOFILL_SUGGESTION = 2,
+  TAB_SWITCHER = 3,
   COUNT,
 };
 
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index 84231aa7..5ff1966 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -40,6 +40,7 @@
 #include "ash/accelerators/accelerator_controller.h"
 #include "ash/shell.h"
 #include "ui/base/accelerators/accelerator.h"
+#include "ui/base/hit_test.h"
 #endif
 
 using ::testing::_;
@@ -1623,6 +1624,8 @@
   // The resize button should be in the top left corner.
   EXPECT_GT(center.x(), resize_button_position.x());
   EXPECT_GT(center.y(), resize_button_position.y());
+  // The resize button hit test should start a top left resizing drag.
+  EXPECT_EQ(HTTOPLEFT, overlay_window_views->GetResizeHTComponent());
 
   // Move the window to the bottom left corner.
   gfx::Rect bottom_left_bounds(0, bottom_right_bounds.y(),
@@ -1640,6 +1643,8 @@
   // The resize button should be in the top right corner.
   EXPECT_LT(center.x(), resize_button_position.x());
   EXPECT_GT(center.y(), resize_button_position.y());
+  // The resize button hit test should start a top right resizing drag.
+  EXPECT_EQ(HTTOPRIGHT, overlay_window_views->GetResizeHTComponent());
 
   // Move the window to the top right corner.
   gfx::Rect top_right_bounds(bottom_right_bounds.x(), 0,
@@ -1657,6 +1662,8 @@
   // The resize button should be in the bottom left corner.
   EXPECT_GT(center.x(), resize_button_position.x());
   EXPECT_LT(center.y(), resize_button_position.y());
+  // The resize button hit test should start a bottom left resizing drag.
+  EXPECT_EQ(HTBOTTOMLEFT, overlay_window_views->GetResizeHTComponent());
 
   // Move the window to the top left corner.
   gfx::Rect top_left_bounds(0, 0, bottom_right_bounds.width(),
@@ -1673,6 +1680,8 @@
   // The resize button should be in the bottom right corner.
   EXPECT_LT(center.x(), resize_button_position.x());
   EXPECT_LT(center.y(), resize_button_position.y());
+  // The resize button hit test should start a bottom right resizing drag.
+  EXPECT_EQ(HTBOTTOMRIGHT, overlay_window_views->GetResizeHTComponent());
 }
 
 #endif  // defined(OS_CHROMEOS)
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/payments_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/payments_section.html
index 2a98ce1..0fea9095 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/payments_section.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/payments_section.html
@@ -42,7 +42,7 @@
       }
     </style>
     <settings-toggle-button id="autofillCreditCardToggle"
-        class="settings-box first"
+        class="settings-box first list-item"
         aria-label="$i18n{creditCards}" no-extension-indicator
         label="$i18n{enableCreditCardsLabel}"
         sub-label="$i18n{enableCreditCardsSublabel}"
@@ -61,6 +61,12 @@
         </extension-controlled-indicator>
       </div>
     </template>
+
+    <div class="settings-box list-item underbar" id="paymentsPagePrivacyLink"
+        hidden$="[[!showPaymentsPagePrivacyLinkText_]]">
+      <div>$i18nRaw{paymentsPagePrivacyLinkText}</div>
+    </div>
+
     <div class="settings-box continuation">
       <h2 class="start">$i18n{creditCards}</h2>
       <paper-button id="addCreditCard"
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/payments_section.js b/chrome/browser/resources/settings/passwords_and_forms_page/payments_section.js
index 2166bfa9..b236b8d 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/payments_section.js
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/payments_section.js
@@ -204,6 +204,18 @@
       },
       readOnly: true,
     },
+
+    /**
+     * True when the payments privacy page link should be shown.
+     * @private {boolean}
+     */
+    showPaymentsPagePrivacyLinkText_: {
+      type: Boolean,
+      value: function() {
+        return loadTimeData.getBoolean('showPaymentsPagePrivacyLinkText');
+      },
+      readOnly: true,
+    },
   },
 
   listeners: {
diff --git a/chrome/browser/supervised_user/supervised_user_service.cc b/chrome/browser/supervised_user/supervised_user_service.cc
index 8ce4c370..d30f6c1 100644
--- a/chrome/browser/supervised_user/supervised_user_service.cc
+++ b/chrome/browser/supervised_user/supervised_user_service.cc
@@ -984,7 +984,7 @@
 }
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
-syncer::ModelTypeSet SupervisedUserService::GetPreferredDataTypes() const {
+syncer::ModelTypeSet SupervisedUserService::GetForcedDataTypes() const {
   if (!ProfileIsSupervised())
     return syncer::ModelTypeSet();
 
diff --git a/chrome/browser/supervised_user/supervised_user_service.h b/chrome/browser/supervised_user/supervised_user_service.h
index da7ef07..75a2d80 100644
--- a/chrome/browser/supervised_user/supervised_user_service.h
+++ b/chrome/browser/supervised_user/supervised_user_service.h
@@ -174,7 +174,7 @@
   void Shutdown() override;
 
   // SyncTypePreferenceProvider implementation:
-  syncer::ModelTypeSet GetPreferredDataTypes() const override;
+  syncer::ModelTypeSet GetForcedDataTypes() const override;
 
 #if !defined(OS_ANDROID)
   // BrowserListObserver implementation:
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 80a1524d..59afa897e 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -281,13 +281,11 @@
 }
 
 syncer::DataTypeController::TypeVector
-ChromeSyncClient::CreateDataTypeControllers(
-    syncer::LocalDeviceInfoProvider* local_device_info_provider) {
+ChromeSyncClient::CreateDataTypeControllers() {
   syncer::ModelTypeSet disabled_types = GetDisabledTypesFromCommandLine();
 
   syncer::DataTypeController::TypeVector controllers =
-      component_factory_->CreateCommonDataTypeControllers(
-          disabled_types, local_device_info_provider);
+      component_factory_->CreateCommonDataTypeControllers(disabled_types);
 
   const base::RepeatingClosure dump_stack = base::BindRepeating(
       &syncer::ReportUnrecoverableError, chrome::GetChannel());
@@ -574,11 +572,6 @@
       return base::WeakPtr<syncer::SyncableService>();
     }
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
-    case syncer::SESSIONS: {
-      return SessionSyncServiceFactory::GetForProfile(profile_)
-          ->GetSyncableService()
-          ->AsWeakPtr();
-    }
     case syncer::PASSWORDS: {
       return password_store_.get()
                  ? password_store_->GetPasswordSyncableService()
diff --git a/chrome/browser/sync/chrome_sync_client.h b/chrome/browser/sync/chrome_sync_client.h
index 66674be..944076a 100644
--- a/chrome/browser/sync/chrome_sync_client.h
+++ b/chrome/browser/sync/chrome_sync_client.h
@@ -50,8 +50,7 @@
   sync_sessions::SessionSyncService* GetSessionSyncService() override;
   bool HasPasswordStore() override;
   base::Closure GetPasswordStateChangedCallback() override;
-  syncer::DataTypeController::TypeVector CreateDataTypeControllers(
-      syncer::LocalDeviceInfoProvider* local_device_info_provider) override;
+  syncer::DataTypeController::TypeVector CreateDataTypeControllers() override;
   autofill::PersonalDataManager* GetPersonalDataManager() override;
   invalidation::InvalidationService* GetInvalidationService() override;
   BookmarkUndoService* GetBookmarkUndoServiceIfExists() override;
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc
index 2f60419..00f18b6 100644
--- a/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -196,8 +196,6 @@
       content::GetNetworkConnectionTracker();
   init_params.debug_identifier = profile->GetDebugName();
   init_params.channel = chrome::GetChannel();
-  init_params.user_events_separate_pref_group =
-      unified_consent::IsUnifiedConsentFeatureEnabled();
 
   bool local_sync_backend_enabled = false;
 // Since the local sync backend is currently only supported on Windows don't
diff --git a/chrome/browser/sync/test/integration/enable_disable_test.cc b/chrome/browser/sync/test/integration/enable_disable_test.cc
index 547aeb5d..cfa57460 100644
--- a/chrome/browser/sync/test/integration/enable_disable_test.cc
+++ b/chrome/browser/sync/test/integration/enable_disable_test.cc
@@ -45,9 +45,8 @@
   // TODO(vitaliii): Do not use such short variable names here (and possibly
   // elsewhere in the file).
   for (ModelType st : selectable_types) {
-    const ModelTypeSet grouped_types = SyncPrefs::ResolvePrefGroups(
-        registered_types, ModelTypeSet(st),
-        unified_consent::IsUnifiedConsentFeatureEnabled());
+    const ModelTypeSet grouped_types =
+        SyncPrefs::ResolvePrefGroups(registered_types, ModelTypeSet(st));
     for (ModelType gt : grouped_types) {
       if (seen.Has(gt)) {
         multi.Put(gt);
@@ -127,10 +126,9 @@
   }
 
   ModelTypeSet ResolveGroup(ModelType type) {
-    return Difference(SyncPrefs::ResolvePrefGroups(
-                          registered_types_, ModelTypeSet(type),
-                          unified_consent::IsUnifiedConsentFeatureEnabled()),
-                      ProxyTypes());
+    return Difference(
+        SyncPrefs::ResolvePrefGroups(registered_types_, ModelTypeSet(type)),
+        ProxyTypes());
   }
 
   ModelTypeSet WithoutMultiTypes(const ModelTypeSet& input) {
diff --git a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
index 0cf7291..4299c88 100644
--- a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
+++ b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
@@ -13,8 +13,6 @@
 #include "base/test/bind_test_util.h"
 #include "chrome/browser/profiles/profile.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/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/test/integration/quiesce_status_change_checker.h"
 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
@@ -25,7 +23,6 @@
 #include "chrome/browser/ui/webui/signin/login_ui_test_utils.h"
 #include "chrome/browser/unified_consent/unified_consent_service_factory.h"
 #include "chrome/common/channel_info.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "components/sync/driver/about_sync_util.h"
 #include "components/sync/engine/sync_string_conversions.h"
 #include "components/unified_consent/feature.h"
@@ -140,8 +137,6 @@
     case SigninType::FAKE_SIGNIN: {
       identity::IdentityManager* identity_manager =
           IdentityManagerFactory::GetForProfile(profile_);
-      ProfileOAuth2TokenService* token_service =
-          ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
 
       // Verify HasPrimaryAccount() separately because
       // MakePrimaryAccountAvailable() below DCHECK fails if there is already
@@ -154,13 +149,11 @@
         // always hand out the same access token string, any new access token
         // acquired later would also be considered invalid.
         if (!identity_manager->HasPrimaryAccountWithRefreshToken()) {
-          identity::SetRefreshTokenForPrimaryAccount(token_service,
-                                                     identity_manager);
+          identity::SetRefreshTokenForPrimaryAccount(identity_manager);
         }
       } else {
         // Authenticate sync client using GAIA credentials.
         identity::MakePrimaryAccountAvailable(
-            SigninManagerFactory::GetForProfile(profile_), token_service,
             identity_manager, username_);
       }
       return true;
@@ -175,7 +168,6 @@
 void ProfileSyncServiceHarness::SignOutPrimaryAccount() {
   DCHECK(!username_.empty());
   identity::ClearPrimaryAccount(
-      SigninManagerFactory::GetForProfile(profile_),
       IdentityManagerFactory::GetForProfile(profile_),
       identity::ClearPrimaryAccountPolicy::REMOVE_ALL_ACCOUNTS);
 }
diff --git a/chrome/browser/sync/test/integration/secondary_account_helper.cc b/chrome/browser/sync/test/integration/secondary_account_helper.cc
index 2792a3d..528ed6b 100644
--- a/chrome/browser/sync/test/integration/secondary_account_helper.cc
+++ b/chrome/browser/sync/test/integration/secondary_account_helper.cc
@@ -6,11 +6,9 @@
 
 #include "base/bind.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/fake_gaia_cookie_manager_service_builder.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 "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/signin/core/browser/fake_gaia_cookie_manager_service.h"
@@ -69,8 +67,6 @@
   identity::IdentityManager* identity_manager =
       IdentityManagerFactory::GetForProfile(profile);
   AccountInfo account_info = identity::MakeAccountAvailable(
-      AccountTrackerServiceFactory::GetForProfile(profile),
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
       identity_manager, email);
   FakeGaiaCookieManagerService* fake_cookie_service =
       static_cast<FakeGaiaCookieManagerService*>(
diff --git a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
index d142e699f..2cdd01d 100644
--- a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
@@ -9,7 +9,6 @@
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/sync/session_sync_service_factory.h"
 #include "chrome/browser/sync/sessions/sync_sessions_router_tab_helper.h"
-#include "chrome/browser/sync/test/integration/feature_toggler.h"
 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
 #include "chrome/browser/sync/test/integration/session_hierarchy_match_checker.h"
 #include "chrome/browser/sync/test/integration/sessions_helper.h"
@@ -22,7 +21,6 @@
 #include "components/history/core/browser/history_types.h"
 #include "components/sessions/core/session_types.h"
 #include "components/sync/base/time.h"
-#include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/protocol/proto_value_conversions.h"
 #include "components/sync/test/fake_server/sessions_hierarchy.h"
 #include "components/sync_sessions/session_sync_service.h"
@@ -71,10 +69,9 @@
   EXPECT_EQ(sample_count, samples->TotalCount());
 }
 
-class SingleClientSessionsSyncTest : public FeatureToggler, public SyncTest {
+class SingleClientSessionsSyncTest : public SyncTest {
  public:
-  SingleClientSessionsSyncTest()
-      : FeatureToggler(switches::kSyncUSSSessions), SyncTest(SINGLE_CLIENT) {}
+  SingleClientSessionsSyncTest() : SyncTest(SINGLE_CLIENT) {}
   ~SingleClientSessionsSyncTest() override {}
 
   void ExpectNavigationChain(const std::vector<GURL>& urls) {
@@ -131,7 +128,7 @@
   DISALLOW_COPY_AND_ASSIGN(SingleClientSessionsSyncTest);
 };
 
-IN_PROC_BROWSER_TEST_P(SingleClientSessionsSyncTest,
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest,
                        RequireProxyTabsForUiDelegate) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(CheckInitialState(0));
@@ -144,7 +141,7 @@
   EXPECT_EQ(nullptr, service->GetOpenTabsUIDelegate());
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientSessionsSyncTest, Sanity) {
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, Sanity) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   ASSERT_TRUE(CheckInitialState(0));
@@ -169,13 +166,13 @@
   WaitForURLOnServer(url);
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientSessionsSyncTest, NoSessions) {
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, NoSessions) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   WaitForHierarchyOnServer(SessionsHierarchy());
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientSessionsSyncTest, ChromeHistory) {
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, ChromeHistory) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   ASSERT_TRUE(CheckInitialState(0));
@@ -184,7 +181,7 @@
   WaitForURLOnServer(GURL(chrome::kChromeUIHistoryURL));
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientSessionsSyncTest, TimestampMatchesHistory) {
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, TimestampMatchesHistory) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   ASSERT_TRUE(CheckInitialState(0));
@@ -216,7 +213,7 @@
   ASSERT_EQ(1, found_navigations);
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientSessionsSyncTest, ResponseCodeIsPreserved) {
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, ResponseCodeIsPreserved) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   ASSERT_TRUE(CheckInitialState(0));
@@ -240,7 +237,7 @@
   ASSERT_EQ(1, found_navigations);
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientSessionsSyncTest, FragmentURLNavigation) {
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, FragmentURLNavigation) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(CheckInitialState(0));
 
@@ -253,7 +250,7 @@
   WaitForURLOnServer(fragment_url);
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientSessionsSyncTest,
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest,
                        NavigationChainForwardBack) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(CheckInitialState(0));
@@ -277,7 +274,7 @@
   ExpectNavigationChain({first_url, second_url});
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientSessionsSyncTest,
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest,
                        NavigationChainAlteredDestructively) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(CheckInitialState(0));
@@ -309,7 +306,7 @@
   ExpectNavigationChain({base_url, second_url});
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientSessionsSyncTest, OpenNewTab) {
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, OpenNewTab) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(CheckInitialState(0));
 
@@ -325,7 +322,7 @@
       SessionsHierarchy({{base_url.spec(), new_tab_url.spec()}}));
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientSessionsSyncTest, OpenNewWindow) {
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, OpenNewWindow) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(CheckInitialState(0));
 
@@ -342,7 +339,7 @@
       SessionsHierarchy({{base_url.spec()}, {new_window_url.spec()}}));
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientSessionsSyncTest, TabMovedToOtherWindow) {
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, TabMovedToOtherWindow) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(CheckInitialState(0));
 
@@ -366,7 +363,7 @@
       {{base_url.spec()}, {new_window_url.spec(), moved_tab_url.spec()}}));
 }
 
-IN_PROC_BROWSER_TEST_P(SingleClientSessionsSyncTest, SourceTabIDSet) {
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, SourceTabIDSet) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(CheckInitialState(0));
 
@@ -402,7 +399,7 @@
 
 // TODO(pavely): This test is flaky. Report failures in
 // https://crbug.com/789129.
-IN_PROC_BROWSER_TEST_P(SingleClientSessionsSyncTest,
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest,
                        DISABLED_CookieJarMismatch) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
@@ -469,8 +466,4 @@
   }
 }
 
-INSTANTIATE_TEST_CASE_P(USS,
-                        SingleClientSessionsSyncTest,
-                        ::testing::Values(false, true));
-
 }  // namespace
diff --git a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
index 35d9b91..dbf054e2 100644
--- a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
@@ -262,6 +262,9 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, NoHistory) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(switches::kSyncUserConsentSeparateType);
+
   const UserEventSpecifics testEvent1 = CreateTestEvent(1);
   const UserEventSpecifics testEvent2 = CreateTestEvent(2);
   const UserEventSpecifics testEvent3 = CreateTestEvent(3);
@@ -290,33 +293,6 @@
   EXPECT_TRUE(ExpectUserEvents({testEvent1, consent1, consent2, testEvent3}));
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, NoUserEvents) {
-  // Enable unified consent feature and the ones it depends on.
-  unified_consent::ScopedUnifiedConsent scoped_unified_consent(
-      unified_consent::UnifiedConsentFeatureState::kEnabledNoBump);
-
-  const UserEventSpecifics testEvent1 = CreateTestEvent(1);
-  const UserEventSpecifics testEvent2 = CreateTestEvent(2);
-  const UserEventSpecifics testEvent3 = CreateTestEvent(3);
-
-  ASSERT_TRUE(SetupSync());
-  syncer::UserEventService* event_service =
-      browser_sync::UserEventServiceFactory::GetForProfile(GetProfile(0));
-  event_service->RecordUserEvent(testEvent1);
-
-  // Wait until the first two events are committed before disabling sync,
-  // because disabled USER_EVENTS drops all uncommitted consents.
-  ASSERT_TRUE(ExpectUserEvents({testEvent1}));
-  ASSERT_TRUE(GetClient(0)->DisableSyncForDatatype(syncer::USER_EVENTS));
-
-  event_service->RecordUserEvent(testEvent2);
-  ASSERT_TRUE(GetClient(0)->EnableSyncForDatatype(syncer::USER_EVENTS));
-  event_service->RecordUserEvent(testEvent3);
-
-  // No |testEvent2| because it was recorded while history was disabled.
-  EXPECT_TRUE(ExpectUserEvents({testEvent1, testEvent3}));
-}
-
 // Test that events that are logged before sync is enabled don't get lost.
 IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest, LoggedBeforeSyncSetup) {
   base::test::ScopedFeatureList feature_list;
diff --git a/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc b/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc
index e7a8a12..7bb01e1b 100644
--- a/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc
@@ -9,12 +9,10 @@
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "chrome/browser/sessions/session_service.h"
-#include "chrome/browser/sync/test/integration/feature_toggler.h"
 #include "chrome/browser/sync/test/integration/passwords_helper.h"
 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
 #include "chrome/browser/sync/test/integration/sessions_helper.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
-#include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/engine/cycle/sync_cycle_snapshot.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -32,10 +30,9 @@
 using sessions_helper::SyncedSessionVector;
 using sessions_helper::WindowsMatch;
 
-class TwoClientSessionsSyncTest : public FeatureToggler, public SyncTest {
+class TwoClientSessionsSyncTest : public SyncTest {
  public:
-  TwoClientSessionsSyncTest()
-      : FeatureToggler(switches::kSyncUSSSessions), SyncTest(TWO_CLIENT) {}
+  TwoClientSessionsSyncTest() : SyncTest(TWO_CLIENT) {}
   ~TwoClientSessionsSyncTest() override {}
 
   void WaitForWindowsInForeignSession(int index, ScopedWindowMap windows) {
@@ -65,7 +62,7 @@
 // (as well as multi-window). We're currently only checking basic single-window/
 // single-tab functionality.
 
-IN_PROC_BROWSER_TEST_P(TwoClientSessionsSyncTest,
+IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest,
                        E2E_ENABLED(SingleClientChanged)) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
@@ -78,7 +75,7 @@
   WaitForForeignSessionsToSync(0, 1);
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientSessionsSyncTest, E2E_ENABLED(AllChanged)) {
+IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, E2E_ENABLED(AllChanged)) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   // Open tabs on all clients and retain window information.
@@ -99,7 +96,7 @@
   }
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientSessionsSyncTest,
+IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest,
                        SingleClientEnabledEncryption) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
@@ -112,7 +109,7 @@
   ASSERT_TRUE(IsEncryptionComplete(1));
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientSessionsSyncTest,
+IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest,
                        SingleClientEnabledEncryptionAndChanged) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
@@ -124,7 +121,7 @@
   WaitForForeignSessionsToSync(0, 1);
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientSessionsSyncTest,
+IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest,
                        BothClientsEnabledEncryption) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
@@ -138,7 +135,7 @@
   ASSERT_TRUE(IsEncryptionComplete(1));
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientSessionsSyncTest, BothChanged) {
+IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, BothChanged) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   ASSERT_TRUE(CheckInitialState(0));
@@ -155,7 +152,7 @@
   WaitForForeignSessionsToSync(0, 1);
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientSessionsSyncTest, DeleteIdleSession) {
+IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, DeleteIdleSession) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   ASSERT_TRUE(CheckInitialState(0));
@@ -176,7 +173,7 @@
   EXPECT_FALSE(GetSessionData(1, &sessions1));
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientSessionsSyncTest, DeleteActiveSession) {
+IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, DeleteActiveSession) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   ASSERT_TRUE(CheckInitialState(0));
@@ -202,7 +199,7 @@
   EXPECT_TRUE(GetSessionData(1, &sessions1));
 }
 
-IN_PROC_BROWSER_TEST_P(TwoClientSessionsSyncTest, MultipleWindowsMultipleTabs) {
+IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, MultipleWindowsMultipleTabs) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   ASSERT_TRUE(CheckInitialState(0));
@@ -219,8 +216,4 @@
   WaitForForeignSessionsToSync(0, 1);
 }
 
-INSTANTIATE_TEST_CASE_P(USS,
-                        TwoClientSessionsSyncTest,
-                        ::testing::Values(false, true));
-
 }  // namespace
diff --git a/chrome/browser/ui/android/infobars/generated_password_saved_infobar.cc b/chrome/browser/ui/android/infobars/generated_password_saved_infobar.cc
index 6489bbe..9312f7f 100644
--- a/chrome/browser/ui/android/infobars/generated_password_saved_infobar.cc
+++ b/chrome/browser/ui/android/infobars/generated_password_saved_infobar.cc
@@ -38,8 +38,11 @@
       static_cast<GeneratedPasswordSavedInfoBarDelegateAndroid*>(delegate());
 
   return Java_GeneratedPasswordSavedInfoBarDelegate_show(
-      env, GetEnumeratedIconId(), base::android::ConvertUTF16ToJavaString(
-                                      env, infobar_delegate->message_text()),
+      env, GetEnumeratedIconId(),
+      base::android::ConvertUTF16ToJavaString(env,
+                                              infobar_delegate->message_text()),
+      base::android::ConvertUTF16ToJavaString(
+          env, infobar_delegate->details_message_text()),
       infobar_delegate->inline_link_range().start(),
       infobar_delegate->inline_link_range().end(),
       base::android::ConvertUTF16ToJavaString(
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index e296fc0..5373afb 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -530,7 +530,7 @@
         chrome::FindBrowserWithWebContents(web_contents()),
         chrome::kPasswordManagerSubPage);
 #else
-    chrome::android::PreferencesLauncher::ShowPasswordSettings();
+    chrome::android::PreferencesLauncher::ShowPasswordSettings(web_contents());
 #endif
   } else if (id == autofill::POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO) {
 #if defined(OS_ANDROID)
diff --git a/chrome/browser/ui/extensions/extension_installed_bubble_browsertest.cc b/chrome/browser/ui/extensions/extension_installed_bubble_browsertest.cc
index e7665a9..eb28d91 100644
--- a/chrome/browser/ui/extensions/extension_installed_bubble_browsertest.cc
+++ b/chrome/browser/ui/extensions/extension_installed_bubble_browsertest.cc
@@ -10,15 +10,12 @@
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_service.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/ui/extensions/extension_installed_bubble.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
 #include "chrome/common/chrome_features.h"
 #include "components/bubble/bubble_controller.h"
 #include "components/bubble/bubble_ui.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/manifest_constants.h"
 #include "services/identity/public/cpp/identity_test_utils.h"
@@ -142,8 +139,6 @@
                        DISABLED_InvokeUi_NoAction) {
   // Sign in to supppress the signin promo.
   identity::MakePrimaryAccountAvailable(
-      SigninManagerFactory::GetForProfile(profile()),
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile()),
       IdentityManagerFactory::GetForProfile(profile()), "test@example.com");
   ShowAndVerifyUi();
 }
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
index 437c8e8f..668269a7 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
@@ -40,7 +40,6 @@
 #include "components/sync/engine/data_type_activation_response.h"
 #include "components/sync/model/data_type_activation_request.h"
 #include "components/sync_sessions/session_sync_service.h"
-#include "components/sync_sessions/sessions_sync_manager.h"
 #include "components/sync_sessions/synced_session.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_utils.h"
diff --git a/chrome/browser/ui/views/chrome_views_delegate.h b/chrome/browser/ui/views/chrome_views_delegate.h
index 91fc28df..64510ab 100644
--- a/chrome/browser/ui/views/chrome_views_delegate.h
+++ b/chrome/browser/ui/views/chrome_views_delegate.h
@@ -35,11 +35,9 @@
                                ui::WindowShowState* show_state) const override;
   void NotifyAccessibilityEvent(views::View* view,
                                 ax::mojom::Event event_type) override;
-#if defined(OS_CHROMEOS) || defined(OS_MACOSX)
+#if defined(OS_CHROMEOS)
   ProcessMenuAcceleratorResult ProcessAcceleratorWhileMenuShowing(
       const ui::Accelerator& accelerator) override;
-#endif
-#if defined(OS_CHROMEOS)
   views::NonClientFrameView* CreateDefaultNonClientFrameView(
       views::Widget* widget) override;
 #endif
diff --git a/chrome/browser/ui/views/chrome_views_delegate_mac.cc b/chrome/browser/ui/views/chrome_views_delegate_mac.cc
index 570266e1..65789e2 100644
--- a/chrome/browser/ui/views/chrome_views_delegate_mac.cc
+++ b/chrome/browser/ui/views/chrome_views_delegate_mac.cc
@@ -17,19 +17,3 @@
 bool ChromeViewsDelegate::ShouldMirrorArrowsInRTL() const {
   return base::FeatureList::IsEnabled(features::kMacRTL);
 }
-
-views::ViewsDelegate::ProcessMenuAcceleratorResult
-ChromeViewsDelegate::ProcessAcceleratorWhileMenuShowing(
-    const ui::Accelerator& accelerator) {
-  using Result = views::ViewsDelegate::ProcessMenuAcceleratorResult;
-  bool is_modified = accelerator.IsCtrlDown() || accelerator.IsAltDown() ||
-                     accelerator.IsCmdDown();
-
-  // Using an accelerator on Mac closes any open menu. Note that Mac behavior is
-  // different between context menus (which block use of accelerators) and other
-  // types of menus, which close when an accelerator is sent and do repost the
-  // accelerator. In MacViews, this happens naturally because context menus are
-  // (modal) Cocoa menus and other menus are Views menus, which will go through
-  // this code path.
-  return is_modified ? Result::CLOSE_MENU : Result::LEAVE_MENU_OPEN;
-}
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index cd8914c..2554bf0 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -117,6 +117,13 @@
       return window_component;
     }
 
+#if defined(OS_CHROMEOS)
+    // If the resize handle is clicked on, we want to force the hit test to
+    // force a resize drag.
+    if (window->GetResizeHandleControlsBounds().Contains(point))
+      return window->GetResizeHTComponent();
+#endif
+
     // Allows for dragging and resizing the window.
     return (window_component == HTNOWHERE) ? HTCAPTION : window_component;
   }
@@ -810,6 +817,10 @@
   return close_controls_view_->GetMirroredBounds();
 }
 
+gfx::Rect OverlayWindowViews::GetResizeHandleControlsBounds() {
+  return resize_handle_view_->GetMirroredBounds();
+}
+
 gfx::Rect OverlayWindowViews::GetPlayPauseControlsBounds() {
   return play_pause_controls_view_->GetMirroredBounds();
 }
@@ -826,6 +837,10 @@
   return second_custom_controls_view_->GetMirroredBounds();
 }
 
+int OverlayWindowViews::GetResizeHTComponent() const {
+  return resize_handle_view_->GetHTComponent();
+}
+
 ui::Layer* OverlayWindowViews::GetControlsScrimLayer() {
   return controls_scrim_view_->layer();
 }
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.h b/chrome/browser/ui/views/overlay/overlay_window_views.h
index b1f714d..df2914b 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.h
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.h
@@ -65,10 +65,15 @@
 
   // Gets the bounds of the controls.
   gfx::Rect GetCloseControlsBounds();
+  gfx::Rect GetResizeHandleControlsBounds();
   gfx::Rect GetPlayPauseControlsBounds();
   gfx::Rect GetFirstCustomControlsBounds();
   gfx::Rect GetSecondCustomControlsBounds();
 
+  // Gets the proper hit test component when the hit point is on the resize
+  // handle in order to force a drag-to-resize.
+  int GetResizeHTComponent() const;
+
   views::ToggleImageButton* play_pause_controls_view_for_testing() const;
   gfx::Point close_image_position_for_testing() const;
   gfx::Point resize_handle_position_for_testing() const;
diff --git a/chrome/browser/ui/views/overlay/resize_handle_button.cc b/chrome/browser/ui/views/overlay/resize_handle_button.cc
index 9fca4a8..29fd1e8 100644
--- a/chrome/browser/ui/views/overlay/resize_handle_button.cc
+++ b/chrome/browser/ui/views/overlay/resize_handle_button.cc
@@ -7,6 +7,7 @@
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/grit/generated_resources.h"
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/hit_test.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/image/image_skia_operations.h"
@@ -16,7 +17,8 @@
 
 namespace {
 
-const int kResizeHandleButtonSize = 16;
+const int kResizeHandleButtonSize = 36;
+const int kResizeHandleImageSize = 18;
 
 constexpr SkColor kResizeHandleIconColor = SK_ColorWHITE;
 
@@ -26,8 +28,8 @@
 
 ResizeHandleButton::ResizeHandleButton(ButtonListener* listener)
     : ImageButton(listener) {
-  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                    views::ImageButton::ALIGN_MIDDLE);
+  SetImageAlignment(views::ImageButton::ALIGN_LEFT,
+                    views::ImageButton::ALIGN_TOP);
   SetSize(gfx::Size(kResizeHandleButtonSize, kResizeHandleButtonSize));
   SetImageForQuadrant(OverlayWindowViews::WindowQuadrant::kBottomRight);
 
@@ -42,6 +44,22 @@
 
 ResizeHandleButton::~ResizeHandleButton() = default;
 
+int ResizeHandleButton::GetHTComponent() const {
+  if (!current_quadrant_)
+    return HTNOWHERE;
+
+  switch (current_quadrant_.value()) {
+    case OverlayWindowViews::WindowQuadrant::kBottomLeft:
+      return HTTOPRIGHT;
+    case OverlayWindowViews::WindowQuadrant::kBottomRight:
+      return HTTOPLEFT;
+    case OverlayWindowViews::WindowQuadrant::kTopLeft:
+      return HTBOTTOMRIGHT;
+    case OverlayWindowViews::WindowQuadrant::kTopRight:
+      return HTBOTTOMLEFT;
+  }
+}
+
 void ResizeHandleButton::SetPosition(
     const gfx::Size& size,
     OverlayWindowViews::WindowQuadrant quadrant) {
@@ -77,19 +95,27 @@
   current_quadrant_ = quadrant;
 
   gfx::ImageSkia icon = gfx::CreateVectorIcon(
-      kResizeHandleIcon, kResizeHandleButtonSize, kResizeHandleIconColor);
+      kResizeHandleIcon, kResizeHandleImageSize, kResizeHandleIconColor);
   switch (quadrant) {
     case OverlayWindowViews::WindowQuadrant::kBottomLeft:
+      SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
+                        views::ImageButton::ALIGN_TOP);
       break;
     case OverlayWindowViews::WindowQuadrant::kBottomRight:
+      SetImageAlignment(views::ImageButton::ALIGN_LEFT,
+                        views::ImageButton::ALIGN_TOP);
       icon = gfx::ImageSkiaOperations::CreateRotatedImage(
           icon, SkBitmapOperations::ROTATION_270_CW);
       break;
     case OverlayWindowViews::WindowQuadrant::kTopLeft:
+      SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
+                        views::ImageButton::ALIGN_BOTTOM);
       icon = gfx::ImageSkiaOperations::CreateRotatedImage(
           icon, SkBitmapOperations::ROTATION_90_CW);
       break;
     case OverlayWindowViews::WindowQuadrant::kTopRight:
+      SetImageAlignment(views::ImageButton::ALIGN_LEFT,
+                        views::ImageButton::ALIGN_BOTTOM);
       icon = gfx::ImageSkiaOperations::CreateRotatedImage(
           icon, SkBitmapOperations::ROTATION_180_CW);
       break;
diff --git a/chrome/browser/ui/views/overlay/resize_handle_button.h b/chrome/browser/ui/views/overlay/resize_handle_button.h
index 1b3646f..b6b52d9 100644
--- a/chrome/browser/ui/views/overlay/resize_handle_button.h
+++ b/chrome/browser/ui/views/overlay/resize_handle_button.h
@@ -18,6 +18,7 @@
 
   void SetPosition(const gfx::Size& size,
                    OverlayWindowViews::WindowQuadrant quadrant);
+  int GetHTComponent() const;
 
  private:
   void SetImageForQuadrant(OverlayWindowViews::WindowQuadrant quadrant);
diff --git a/chrome/browser/ui/views/tabs/tab_icon.cc b/chrome/browser/ui/views/tabs/tab_icon.cc
index 8c12981..c7cbe32d 100644
--- a/chrome/browser/ui/views/tabs/tab_icon.cc
+++ b/chrome/browser/ui/views/tabs/tab_icon.cc
@@ -48,15 +48,13 @@
          url.host_piece() != chrome::kChromeUIAppLauncherPageHost;
 }
 
-// Fraction of the icon height used for the throbber.
-constexpr float kThrobberBoundsFraction = 1 / 8.0f;
-
-// Returns a rect that covers the bottom quarter of |bounds|.
+// Returns a rect in which the throbber should be painted.
 gfx::RectF GetThrobberBounds(const gfx::Rect& bounds) {
   gfx::RectF throbber_bounds(bounds);
-  const float height = bounds.height() * kThrobberBoundsFraction;
-  throbber_bounds.set_y(bounds.bottom() - height);
-  throbber_bounds.set_height(height);
+  constexpr float kThrobberHeightDp = 2;
+  // The throbber starts 1dp below the tab icon.
+  throbber_bounds.set_y(bounds.bottom() + 1);
+  throbber_bounds.set_height(kThrobberHeightDp);
   return throbber_bounds;
 }
 
@@ -337,8 +335,8 @@
   flags.setStyle(cc::PaintFlags::kFill_Style);
   flags.setAntiAlias(true);
 
-  canvas->DrawRoundRect(bounds, bounds.height() * kThrobberBoundsFraction,
-                        flags);
+  constexpr float kFaviconPlaceholderRadiusDp = 4;
+  canvas->DrawRoundRect(bounds, kFaviconPlaceholderRadiusDp, flags);
 }
 
 bool TabIcon::MaybePaintFavicon(gfx::Canvas* canvas,
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
index 5d79f75..ec6e4d9 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
@@ -366,8 +366,6 @@
                                          kResponseRegisterComplete);
 
     identity::MakePrimaryAccountAvailable(
-        SigninManagerFactory::GetForProfile(browser()->profile()),
-        ProfileOAuth2TokenServiceFactory::GetForProfile(browser()->profile()),
         IdentityManagerFactory::GetForProfile(browser()->profile()),
         kSampleUser);
 
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index e9c9fd5..47982ad 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -1750,8 +1750,6 @@
     {"bookmarksCheckboxLabel", IDS_SETTINGS_BOOKMARKS_CHECKBOX_LABEL},
     {"passwordsCheckboxLabel", IDS_SETTINGS_PASSWORDS_CHECKBOX_LABEL},
     {"openTabsCheckboxLabel", IDS_SETTINGS_OPEN_TABS_CHECKBOX_LABEL},
-    {"userEventsCheckboxLabel", IDS_SETTINGS_USER_EVENTS_CHECKBOX_LABEL},
-    {"userEventsCheckboxText", IDS_SETTINGS_USER_EVENTS_CHECKBOX_TEXT},
     {"driveSuggestPref", IDS_DRIVE_SUGGEST_PREF},
     {"driveSuggestPrefDesc", IDS_DRIVE_SUGGEST_PREF_DESC},
     {"manageSyncedDataTitle", IDS_SETTINGS_MANAGE_SYNCED_DATA_TITLE},
@@ -1899,6 +1897,16 @@
   html_source->AddBoolean("isAccountManagerEnabled",
                           chromeos::switches::IsAccountManagerEnabled());
 #endif
+
+  base::string16 payment_privacy_cross_link = l10n_util::GetStringFUTF16(
+      IDS_SETTINGS_PAYMENTS_PAGE_PRIVACY_LINK_TEXT,
+      base::ASCIIToUTF16(autofill::kPrivacySettingsURL));
+  html_source->AddString("paymentsPagePrivacyLinkText",
+                         payment_privacy_cross_link);
+  html_source->AddBoolean(
+      "showPaymentsPagePrivacyLinkText",
+      base::FeatureList::IsEnabled(
+          autofill::features::kAutofillEnableAccountWalletStorage));
 }
 
 void AddPrintingStrings(content::WebUIDataSource* html_source) {
diff --git a/chrome/browser/ui/webui/settings/people_handler_unittest.cc b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
index 227ffbf3..d49102be 100644
--- a/chrome/browser/ui/webui/settings/people_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
@@ -108,7 +108,6 @@
   result.SetBoolean("tabsSynced", types.Has(syncer::PROXY_TABS));
   result.SetBoolean("themesSynced", types.Has(syncer::THEMES));
   result.SetBoolean("typedUrlsSynced", types.Has(syncer::TYPED_URLS));
-  result.SetBoolean("userEventsSynced", types.Has(syncer::USER_EVENTS));
   result.SetBoolean("paymentsIntegrationEnabled", false);
   std::string args;
   base::JSONWriter::Write(result, &args);
@@ -156,7 +155,6 @@
   CheckBool(dictionary, "tabsSynced", types.Has(syncer::PROXY_TABS));
   CheckBool(dictionary, "themesSynced", types.Has(syncer::THEMES));
   CheckBool(dictionary, "typedUrlsSynced", types.Has(syncer::TYPED_URLS));
-  CheckBool(dictionary, "userEventsSynced", types.Has(syncer::USER_EVENTS));
 }
 
 }  // namespace
@@ -884,7 +882,6 @@
   CheckBool(dictionary, "tabsRegistered", true);
   CheckBool(dictionary, "themesRegistered", true);
   CheckBool(dictionary, "typedUrlsRegistered", true);
-  CheckBool(dictionary, "userEventsRegistered", true);
   CheckBool(dictionary, "paymentsIntegrationEnabled", true);
   CheckBool(dictionary, "passphraseRequired", false);
   CheckBool(dictionary, "passphraseTypeIsCustom", false);
diff --git a/chrome/build/chrome.x64.orderfile.sha1 b/chrome/build/chrome.x64.orderfile.sha1
index ee36fbc9..a88abad 100644
--- a/chrome/build/chrome.x64.orderfile.sha1
+++ b/chrome/build/chrome.x64.orderfile.sha1
@@ -1 +1 @@
-e599dd40cd991030e52676e8656d96c980147a88
\ No newline at end of file
+5acb808c8a55ce204641ae4aa32bb85d4e128370
\ No newline at end of file
diff --git a/chrome/build/chrome.x86.orderfile.sha1 b/chrome/build/chrome.x86.orderfile.sha1
index 828edde..c631311 100644
--- a/chrome/build/chrome.x86.orderfile.sha1
+++ b/chrome/build/chrome.x86.orderfile.sha1
@@ -1 +1 @@
-1fd5a2f8384c8130906163e95c267adcdfa7b436
\ No newline at end of file
+706611f57960570147dc4a86ad3a386146d3783c
\ No newline at end of file
diff --git a/chrome/build/chrome_child.x64.orderfile.sha1 b/chrome/build/chrome_child.x64.orderfile.sha1
index 4d9ce23..76ef9df3 100644
--- a/chrome/build/chrome_child.x64.orderfile.sha1
+++ b/chrome/build/chrome_child.x64.orderfile.sha1
@@ -1 +1 @@
-a0ff6a0859090f8a990b54acf18310a9bd8b2c85
\ No newline at end of file
+812a701e2c9b558038c7452a88aac048227159d2
\ No newline at end of file
diff --git a/chrome/build/chrome_child.x86.orderfile.sha1 b/chrome/build/chrome_child.x86.orderfile.sha1
index e3788d52..bf8157f 100644
--- a/chrome/build/chrome_child.x86.orderfile.sha1
+++ b/chrome/build/chrome_child.x86.orderfile.sha1
@@ -1 +1 @@
-f7e302e7d120961ef0cda7faeb1f53bcdad01a33
\ No newline at end of file
+49956c0413aa694c4270c946372ec69454365b0e
\ No newline at end of file
diff --git a/chrome/common/extensions/api/browsing_data.json b/chrome/common/extensions/api/browsing_data.json
index 10fd0b71..3e62daa 100644
--- a/chrome/common/extensions/api/browsing_data.json
+++ b/chrome/common/extensions/api/browsing_data.json
@@ -54,7 +54,12 @@
           "cache": {
             "type": "boolean",
             "optional": true,
-            "description": "The browser's cache. Note: when removing data, this clears the <em>entire</em> cache: it is not limited to the range you specify."
+            "description": "The browser's cache."
+          },
+          "cacheStorage": {
+            "type": "boolean",
+            "optional": true,
+            "description": "Cache storage"
           },
           "cookies": {
             "type": "boolean",
@@ -210,6 +215,24 @@
         ]
       },
       {
+        "name": "removeCacheStorage",
+        "description": "Clears websites' cache storage data.",
+        "type": "function",
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when websites' cache storage has been cleared.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
         "name": "removeCookies",
         "description": "Clears the browser's cookies and server-bound certificates modified within a particular timeframe.",
         "type": "function",
@@ -372,6 +395,24 @@
         ]
       },
       {
+        "name": "removeServiceWorkers",
+        "description": "Clears websites' service workers.",
+        "type": "function",
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when websites' service workers have been cleared.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
         "name": "removeWebSQL",
         "description": "Clears websites' WebSQL data.",
         "type": "function",
diff --git a/chrome/common/extensions/docs/examples/api/browsingData/basic/popup.js b/chrome/common/extensions/docs/examples/api/browsingData/basic/popup.js
index 8dcb7a3..ee7b2654 100644
--- a/chrome/common/extensions/docs/examples/api/browsingData/basic/popup.js
+++ b/chrome/common/extensions/docs/examples/api/browsingData/basic/popup.js
@@ -109,21 +109,25 @@
     if (removal_start !== undefined) {
       this.button_.setAttribute('disabled', 'disabled');
       this.button_.innerText = 'Clearing...';
-      chrome.browsingData.remove({ "since" : removal_start }, {
-        "appcache": true,
-        "cache": true,
-        "cookies": true,
-        "downloads": true,
-        "fileSystems": true,
-        "formData": true,
-        "history": true,
-        "indexedDB": true,
-        "localStorage": true,
-        "serverBoundCertificates": true,
-        "pluginData": true,
-        "passwords": true,
-        "webSQL": true
-      }, this.handleCallback_.bind(this));
+      chrome.browsingData.remove(
+          {'since': removal_start}, {
+            'appcache': true,
+            'cache': true,
+            'cacheStorage': true,
+            'cookies': true,
+            'downloads': true,
+            'fileSystems': true,
+            'formData': true,
+            'history': true,
+            'indexedDB': true,
+            'localStorage': true,
+            'serverBoundCertificates': true,
+            'serviceWorkers': true,
+            'pluginData': true,
+            'passwords': true,
+            'webSQL': true
+          },
+          this.handleCallback_.bind(this));
     }
   }
 };
diff --git a/chrome/common/extensions/docs/templates/intros/browsingData.html b/chrome/common/extensions/docs/templates/intros/browsingData.html
index 2f783d22..d8bf735 100644
--- a/chrome/common/extensions/docs/templates/intros/browsingData.html
+++ b/chrome/common/extensions/docs/templates/intros/browsingData.html
@@ -43,6 +43,7 @@
 }, {
   "appcache": true,
   "cache": true,
+  "cacheStorage": true,
   "cookies": true,
   "downloads": true,
   "fileSystems": true,
@@ -52,6 +53,7 @@
   "localStorage": true,
   "pluginData": true,
   "passwords": true,
+  "serviceWorkers": true,
   "webSQL": true
 }, callback);</pre>
 
@@ -137,6 +139,7 @@
 }, {
   "appcache": true,
   "cache": true,
+  "cacheStorage": true,
   "cookies": true,
   "downloads": true,
   "fileSystems": true,
@@ -147,6 +150,7 @@
   "serverBoundCertificates": true,
   "pluginData": true,
   "passwords": true,
+  "serviceWorkers": true,
   "webSQL": true
 }, callback);</pre>
 
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
index e8a746e..37f354b 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
@@ -303,7 +303,7 @@
         Assert.assertNotNull("Cannot load the URL in a null tab", tab);
         final AtomicInteger result = new AtomicInteger();
 
-        ChromeTabUtils.waitForTabPageLoaded(tab, new Runnable() {
+        ChromeTabUtils.waitForTabPageLoaded(tab, url, new Runnable() {
             @Override
             public void run() {
                 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java
index 690b7529..cc688bc 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java
@@ -23,7 +23,6 @@
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.Tab.TabHidingType;
-import org.chromium.chrome.browser.tab.TabObserver;
 import org.chromium.chrome.browser.tab.TabWebContentsObserver;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModel;
@@ -46,6 +45,8 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
+import javax.annotation.Nullable;
+
 /**
  * A utility class that contains methods generic to all Tabs tests.
  */
@@ -99,8 +100,8 @@
         }
 
         @Override
-        public void onPageLoadFinished(Tab tab) {
-            if (mExpectedUrl == null || TextUtils.equals(tab.getUrl(), mExpectedUrl)) {
+        public void onPageLoadFinished(Tab tab, String url) {
+            if (mExpectedUrl == null || TextUtils.equals(url, mExpectedUrl)) {
                 mCallback.notifyCalled();
                 tab.removeObserver(this);
             }
@@ -113,14 +114,47 @@
     }
 
     /**
-     * Waits for the given tab to finish loading its current page.
+     * Waits for the given tab to finish loading the given URL, or, if the given URL is
+     * null, waits for the current page to load.
      *
      * @param tab The tab to wait for the page loading to be complete.
      * @param url The URL that will be waited to load for.  Pass in null if loading the
      *            current page is sufficient.
      */
-    public static void waitForTabPageLoaded(final Tab tab, final String url)
+    public static void waitForTabPageLoaded(final Tab tab, @Nullable final String url)
             throws InterruptedException {
+        waitForTabPageLoaded(tab, url, null, ScalableTimeout.scaleTimeout(10));
+    }
+
+    /**
+     * Waits for the given tab to load the given URL, or, if the given URL is null, waits
+     * for the triggered load to complete.
+     *
+     * @param tab The tab to wait for the page loading to be complete.
+     * @param url The expected url of the loaded page.  Pass in null if loading the
+     *            current page is sufficient.
+     * @param loadTrigger The trigger action that will result in a page load finished event
+     *                    to be fired (not run on the UI thread by default).
+     */
+    public static void waitForTabPageLoaded(final Tab tab, @Nullable final String url,
+            @Nullable Runnable loadTrigger) throws InterruptedException {
+        waitForTabPageLoaded(tab, url, loadTrigger, CallbackHelper.WAIT_TIMEOUT_SECONDS);
+    }
+
+    /**
+     * Waits for the given tab to load the given URL, or, if the given URL is null, waits
+     * for the triggered load to complete.
+     *
+     * @param tab The tab to wait for the page loading to be complete.
+     * @param url The expected url of the loaded page.  Pass in null if loading the
+     *            current page is sufficient.
+     * @param loadTrigger The trigger action that will result in a page load finished event
+     *                    to be fired (not run on the UI thread by default).  Pass in null if the
+     *                    load is triggered externally.
+     * @param secondsToWait The number of seconds to wait for the page to be loaded.
+     */
+    public static void waitForTabPageLoaded(final Tab tab, @Nullable final String url,
+            @Nullable Runnable loadTrigger, long secondsToWait) throws InterruptedException {
         Assert.assertFalse(ThreadUtils.runningOnUiThread());
 
         final CountDownLatch loadStoppedLatch = new CountDownLatch(1);
@@ -128,17 +162,19 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                if (loadComplete(tab, url)) {
+                // Don't check for the load being already complete if there is a trigger to run.
+                if (loadTrigger == null && loadComplete(tab, url)) {
                     loadedCallback.notifyCalled();
                     return;
                 }
                 tab.addObserver(new TabPageLoadedObserver(loadedCallback, url, loadStoppedLatch));
             }
         });
-
+        if (loadTrigger != null) {
+            loadTrigger.run();
+        }
         try {
-            loadedCallback.waitForCallback(
-                    0, 1, ScalableTimeout.scaleTimeout(10), TimeUnit.SECONDS);
+            loadedCallback.waitForCallback(0, 1, secondsToWait, TimeUnit.SECONDS);
         } catch (TimeoutException e) {
             // In the event that:
             //  1) the tab is on the correct page
@@ -166,51 +202,6 @@
     }
 
     /**
-     * Waits for the given tab to finish loading its current page.
-     *
-     * @param tab The tab to wait for the page loading to be complete.
-     * @param loadTrigger The trigger action that will result in a page load finished event
-     *                    to be fired (not run on the UI thread by default).
-     */
-    public static void waitForTabPageLoaded(final Tab tab, Runnable loadTrigger)
-            throws InterruptedException {
-        waitForTabPageLoaded(tab, loadTrigger, CallbackHelper.WAIT_TIMEOUT_SECONDS);
-    }
-
-    /**
-     * Waits for the given tab to finish loading its current page.
-     *
-     * @param tab The tab to wait for the page loading to be complete.
-     * @param loadTrigger The trigger action that will result in a page load finished event
-     *                    to be fired (not run on the UI thread by default).
-     * @param secondsToWait The number of seconds to wait for the page to be loaded.
-     */
-    public static void waitForTabPageLoaded(
-            final Tab tab, Runnable loadTrigger, long secondsToWait)
-            throws InterruptedException {
-        final CountDownLatch countDownLatch = new CountDownLatch(1);
-        final CallbackHelper loadedCallback = new CallbackHelper();
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                TabObserver observer =
-                        new TabPageLoadedObserver(loadedCallback, null, countDownLatch);
-                tab.addObserver(observer);
-            }
-        });
-        loadTrigger.run();
-        try {
-            loadedCallback.waitForCallback(0, 1, secondsToWait, TimeUnit.SECONDS);
-        } catch (TimeoutException e) {
-            Assert.fail("Page did not load.  Tab information at time of failure --"
-                    + " url: " + tab.getUrl() + ", load progress: " + tab.getProgress()
-                    + ", is loading: " + Boolean.toString(tab.isLoading())
-                    + ", web contents loading: "
-                    + Boolean.toString(tab.getWebContents().isLoadingToDifferentDocument()));
-        }
-    }
-
-    /**
      * Waits for the given tab to start loading its current page.
      *
      * @param tab The tab to wait for the page loading to be started.
@@ -447,7 +438,7 @@
         newTabFromMenu(instrumentation, activity, incognito, false);
 
         final Tab tab = activity.getActivityTab();
-        waitForTabPageLoaded(tab, new Runnable(){
+        waitForTabPageLoaded(tab, url, new Runnable() {
             @Override
             public void run() {
                 loadUrlOnUiThread(tab, url);
@@ -469,8 +460,7 @@
      * Ensure that at least some given number of tabs are open.
      */
     public static void ensureNumOpenTabs(Instrumentation instrumentation,
-            ChromeTabbedActivity activity, int newCount)
-            throws InterruptedException {
+            ChromeTabbedActivity activity, int newCount) throws InterruptedException {
         int curCount = getNumOpenTabs(activity);
         if (curCount < newCount) {
             newTabsFromMenu(instrumentation, activity, newCount - curCount);
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/TabLoadObserver.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/TabLoadObserver.java
index fa55936..c47b6d2 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/TabLoadObserver.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/TabLoadObserver.java
@@ -50,7 +50,7 @@
     }
 
     @Override
-    public void onPageLoadFinished(Tab tab) {
+    public void onPageLoadFinished(Tab tab, String url) {
         mTabLoadFinishedCallback.notifyCalled();
     }
 
diff --git a/chrome/test/data/extensions/platform_apps/web_view/spatial_navigation_state_api/main.js b/chrome/test/data/extensions/platform_apps/web_view/spatial_navigation_state_api/main.js
index 4906a9d..23fdcff4 100644
--- a/chrome/test/data/extensions/platform_apps/web_view/spatial_navigation_state_api/main.js
+++ b/chrome/test/data/extensions/platform_apps/web_view/spatial_navigation_state_api/main.js
@@ -14,7 +14,7 @@
 function secondCheck(e) {
   chrome.test.log('After RIGHT key is pressed once');
   if (e.message == 'focused:1') {
-    // setup next tests
+    // setup next test
     var webview = document.querySelector('webview');
     webview.removeEventListener('consolemessage', secondCheck);
     webview.addEventListener('consolemessage', thirdCheck);
@@ -28,24 +28,39 @@
 function thirdCheck(e) {
   chrome.test.log('After RIGHT key is pressed once more');
   if (e.message == 'focused:2') {
-    // setup next tests
+    chrome.test.sendMessage('TEST_STEP_PASSED');
+
+    // setup next test
     var webview = document.querySelector('webview');
     webview.removeEventListener('consolemessage', thirdCheck);
     webview.setSpatialNavigationEnabled(false);
-    webview.isSpatialNavigationEnabled(fourthCheck);
-    webview.addEventListener('consolemessage', fifthCheck);
 
-    chrome.test.sendMessage('TEST_STEP_PASSED');
+    // send message via the same IPC channel as setSpatialNavigationEnabled and
+    // wait for reply before checking the state with
+    // getSpatialNavigationEnabled. Required to make sure that the
+    // setSpatialNavigationEnabled call has reached the renderer process.
+    window.onmessage = onMessage;
+    webview.contentWindow.postMessage('{}', '*');
   } else {
     chrome.test.sendMessage('TEST_STEP_FAILED');
   }
 }
 
+var onMessage = function(e) {
+  chrome.test.log('Received message back from renderer');
+  var webview = document.querySelector('webview');
+  webview.isSpatialNavigationEnabled(fourthCheck);
+};
+
 function fourthCheck(spatialNavigationEnabled) {
   chrome.test.log('Spatial navigation disabled');
   if (spatialNavigationEnabled) {
     chrome.test.sendMessage('TEST_STEP_FAILED');
   } else {
+    // setup next test
+    var webview = document.querySelector('webview');
+    webview.addEventListener('consolemessage', fifthCheck);
+
     chrome.test.sendMessage('TEST_STEP_PASSED');
   }
 }
@@ -67,8 +82,8 @@
     webview.removeEventListener('loadstop', onLoadStop);
     chrome.test.sendMessage('WebViewTest.LAUNCHED');
 
-    webview.isSpatialNavigationEnabled(firstCheck);
     webview.focus();
+    webview.isSpatialNavigationEnabled(firstCheck);
   };
 
   webview.addEventListener('loadstop', onLoadStop);
@@ -90,6 +105,9 @@
             console.log('focused:'+ev.target.id);
           };
         });
+        window.onmessage = function(e) {
+          e.source.postMessage('{}', '*');
+        };
         </script>
     </body>
   `;
diff --git a/chrome/test/data/webui/settings/payments_section_test.js b/chrome/test/data/webui/settings/payments_section_test.js
index e3e25bd..85f0f03 100644
--- a/chrome/test/data/webui/settings/payments_section_test.js
+++ b/chrome/test/data/webui/settings/payments_section_test.js
@@ -618,5 +618,19 @@
       // All migration requirements are met, verify migration button is shown.
       assertFalse(section.$$('#migrateCreditCards').hidden);
     });
+
+    test('verifyPrivacyLinkHidden', function() {
+      // By default, the link should not be visible.
+      const section = createPaymentsSection([], {});
+
+      assertTrue(section.$$('#paymentsPagePrivacyLink').hidden);
+    });
+
+    test('verifyPrivacyLinkVisible', function() {
+      loadTimeData.overrideValues({showPaymentsPagePrivacyLinkText: true});
+      const section = createPaymentsSection([], {});
+
+      assertFalse(section.$$('#paymentsPagePrivacyLink').hidden);
+    });
   });
 });
diff --git a/chromeos/components/tether/asynchronous_shutdown_object_container.h b/chromeos/components/tether/asynchronous_shutdown_object_container.h
index 34af7ad9..1d5f1665 100644
--- a/chromeos/components/tether/asynchronous_shutdown_object_container.h
+++ b/chromeos/components/tether/asynchronous_shutdown_object_container.h
@@ -12,7 +12,6 @@
 namespace tether {
 
 class TetherHostFetcher;
-class BleConnectionManager;
 class DisconnectTetheringRequestSender;
 class NetworkConfigurationRemover;
 class WifiHotspotDisconnector;
@@ -32,7 +31,6 @@
   virtual void Shutdown(const base::Closure& shutdown_complete_callback) = 0;
 
   virtual TetherHostFetcher* tether_host_fetcher() = 0;
-  virtual BleConnectionManager* ble_connection_manager() = 0;
   virtual DisconnectTetheringRequestSender*
   disconnect_tethering_request_sender() = 0;
   virtual NetworkConfigurationRemover* network_configuration_remover() = 0;
diff --git a/chromeos/components/tether/asynchronous_shutdown_object_container_impl.cc b/chromeos/components/tether/asynchronous_shutdown_object_container_impl.cc
index 67c1a9f9..b6bdb4a2 100644
--- a/chromeos/components/tether/asynchronous_shutdown_object_container_impl.cc
+++ b/chromeos/components/tether/asynchronous_shutdown_object_container_impl.cc
@@ -8,7 +8,6 @@
 #include "chromeos/chromeos_features.h"
 #include "chromeos/components/tether/ble_advertisement_device_queue.h"
 #include "chromeos/components/tether/ble_advertiser_impl.h"
-#include "chromeos/components/tether/ble_connection_manager.h"
 #include "chromeos/components/tether/ble_connection_metrics_logger.h"
 #include "chromeos/components/tether/ble_scanner_impl.h"
 #include "chromeos/components/tether/ble_service_data_helper_impl.h"
@@ -127,14 +126,6 @@
                     ble_service_data_helper_.get(),
                     ble_synchronizer_.get(),
                     tether_host_fetcher_)),
-      ble_connection_manager_(
-          base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)
-              ? nullptr
-              : std::make_unique<BleConnectionManager>(
-                    adapter,
-                    ble_advertisement_device_queue_.get(),
-                    ble_advertiser_.get(),
-                    ble_scanner_.get())),
       ble_connection_metrics_logger_(
           base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)
               ? nullptr
@@ -143,7 +134,6 @@
           DisconnectTetheringRequestSenderImpl::Factory::NewInstance(
               device_sync_client,
               secure_channel_client,
-              ble_connection_manager_.get(),
               tether_host_fetcher_)),
       network_configuration_remover_(
           std::make_unique<NetworkConfigurationRemover>(
@@ -153,22 +143,15 @@
           network_state_handler,
           pref_service,
           network_configuration_remover_.get())) {
-  if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
-    ble_connection_manager_->AddMetricsObserver(
-        ble_connection_metrics_logger_.get());
-  }
 }
 
 AsynchronousShutdownObjectContainerImpl::
     ~AsynchronousShutdownObjectContainerImpl() {
+  disconnect_tethering_request_sender_->RemoveObserver(this);
   if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
-    ble_connection_manager_->RemoveMetricsObserver(
-        ble_connection_metrics_logger_.get());
     ble_advertiser_->RemoveObserver(this);
     ble_scanner_->RemoveObserver(this);
   }
-
-  disconnect_tethering_request_sender_->RemoveObserver(this);
 }
 
 void AsynchronousShutdownObjectContainerImpl::Shutdown(
@@ -193,13 +176,6 @@
   return tether_host_fetcher_;
 }
 
-BleConnectionManager*
-AsynchronousShutdownObjectContainerImpl::ble_connection_manager() {
-  return base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)
-             ? nullptr
-             : ble_connection_manager_.get();
-}
-
 DisconnectTetheringRequestSender*
 AsynchronousShutdownObjectContainerImpl::disconnect_tethering_request_sender() {
   return disconnect_tethering_request_sender_.get();
diff --git a/chromeos/components/tether/asynchronous_shutdown_object_container_impl.h b/chromeos/components/tether/asynchronous_shutdown_object_container_impl.h
index 4e4ca1a..311dd02 100644
--- a/chromeos/components/tether/asynchronous_shutdown_object_container_impl.h
+++ b/chromeos/components/tether/asynchronous_shutdown_object_container_impl.h
@@ -51,7 +51,6 @@
 namespace tether {
 
 class BleAdvertisementDeviceQueue;
-class BleConnectionManager;
 class BleConnectionMetricsLogger;
 class NetworkConfigurationRemover;
 class TetherHostFetcher;
@@ -102,7 +101,6 @@
   // AsynchronousShutdownObjectContainer:
   void Shutdown(const base::Closure& shutdown_complete_callback) override;
   TetherHostFetcher* tether_host_fetcher() override;
-  BleConnectionManager* ble_connection_manager() override;
   DisconnectTetheringRequestSender* disconnect_tethering_request_sender()
       override;
   NetworkConfigurationRemover* network_configuration_remover() override;
@@ -151,7 +149,6 @@
   std::unique_ptr<secure_channel::BleSynchronizerBase> ble_synchronizer_;
   std::unique_ptr<BleAdvertiser> ble_advertiser_;
   std::unique_ptr<BleScanner> ble_scanner_;
-  std::unique_ptr<BleConnectionManager> ble_connection_manager_;
   std::unique_ptr<BleConnectionMetricsLogger> ble_connection_metrics_logger_;
   std::unique_ptr<DisconnectTetheringRequestSender>
       disconnect_tethering_request_sender_;
diff --git a/chromeos/components/tether/connect_tethering_operation.cc b/chromeos/components/tether/connect_tethering_operation.cc
index ca22697..140425d6 100644
--- a/chromeos/components/tether/connect_tethering_operation.cc
+++ b/chromeos/components/tether/connect_tethering_operation.cc
@@ -40,7 +40,6 @@
     cryptauth::RemoteDeviceRef device_to_connect,
     device_sync::DeviceSyncClient* device_sync_client,
     secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* connection_manager,
     TetherHostResponseRecorder* tether_host_response_recorder,
     bool setup_required) {
   if (!factory_instance_) {
@@ -48,7 +47,7 @@
   }
   return factory_instance_->BuildInstance(
       device_to_connect, device_sync_client, secure_channel_client,
-      connection_manager, tether_host_response_recorder, setup_required);
+      tether_host_response_recorder, setup_required);
 }
 
 // static
@@ -62,27 +61,24 @@
     cryptauth::RemoteDeviceRef device_to_connect,
     device_sync::DeviceSyncClient* device_sync_client,
     secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* connection_manager,
     TetherHostResponseRecorder* tether_host_response_recorder,
     bool setup_required) {
   return base::WrapUnique(new ConnectTetheringOperation(
       device_to_connect, device_sync_client, secure_channel_client,
-      connection_manager, tether_host_response_recorder, setup_required));
+      tether_host_response_recorder, setup_required));
 }
 
 ConnectTetheringOperation::ConnectTetheringOperation(
     cryptauth::RemoteDeviceRef device_to_connect,
     device_sync::DeviceSyncClient* device_sync_client,
     secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* connection_manager,
     TetherHostResponseRecorder* tether_host_response_recorder,
     bool setup_required)
     : MessageTransferOperation(
           cryptauth::RemoteDeviceRefList{device_to_connect},
           secure_channel::ConnectionPriority::kHigh,
           device_sync_client,
-          secure_channel_client,
-          connection_manager),
+          secure_channel_client),
       remote_device_(device_to_connect),
       tether_host_response_recorder_(tether_host_response_recorder),
       clock_(base::DefaultClock::GetInstance()),
diff --git a/chromeos/components/tether/connect_tethering_operation.h b/chromeos/components/tether/connect_tethering_operation.h
index 882ee4e47..b8b960fc 100644
--- a/chromeos/components/tether/connect_tethering_operation.h
+++ b/chromeos/components/tether/connect_tethering_operation.h
@@ -12,7 +12,6 @@
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/time/clock.h"
-#include "chromeos/components/tether/ble_connection_manager.h"
 #include "chromeos/components/tether/message_transfer_operation.h"
 #include "components/cryptauth/remote_device_ref.h"
 
@@ -56,7 +55,6 @@
         cryptauth::RemoteDeviceRef device_to_connect,
         device_sync::DeviceSyncClient* device_sync_client,
         secure_channel::SecureChannelClient* secure_channel_client,
-        BleConnectionManager* connection_manager,
         TetherHostResponseRecorder* tether_host_response_recorder,
         bool setup_required);
 
@@ -67,7 +65,6 @@
         cryptauth::RemoteDeviceRef devices_to_connect,
         device_sync::DeviceSyncClient* device_sync_client,
         secure_channel::SecureChannelClient* secure_channel_client,
-        BleConnectionManager* connection_manager,
         TetherHostResponseRecorder* tether_host_response_recorder,
         bool setup_required);
 
@@ -98,7 +95,6 @@
       cryptauth::RemoteDeviceRef device_to_connect,
       device_sync::DeviceSyncClient* device_sync_client,
       secure_channel::SecureChannelClient* secure_channel_client,
-      BleConnectionManager* connection_manager,
       TetherHostResponseRecorder* tether_host_response_recorder,
       bool setup_required);
 
diff --git a/chromeos/components/tether/connect_tethering_operation_unittest.cc b/chromeos/components/tether/connect_tethering_operation_unittest.cc
index 3f4e8d3..d262164 100644
--- a/chromeos/components/tether/connect_tethering_operation_unittest.cc
+++ b/chromeos/components/tether/connect_tethering_operation_unittest.cc
@@ -138,7 +138,7 @@
 
     operation_ = base::WrapUnique(new ConnectTetheringOperation(
         test_device_, fake_device_sync_client_.get(),
-        fake_secure_channel_client_.get(), fake_ble_connection_manager_.get(),
+        fake_secure_channel_client_.get(),
         mock_tether_host_response_recorder_.get(), false /* setup_required */));
     operation_->AddObserver(test_observer_.get());
 
@@ -318,7 +318,7 @@
 TEST_F(ConnectTetheringOperationTest, DISABLED_TestOperation_SetupRequired) {
   operation_ = base::WrapUnique(new ConnectTetheringOperation(
       test_device_, fake_device_sync_client_.get(),
-      fake_secure_channel_client_.get(), fake_ble_connection_manager_.get(),
+      fake_secure_channel_client_.get(),
       mock_tether_host_response_recorder_.get(), true /* setup_required */));
   VerifyResponseTimeoutSeconds(true /* setup_required */);
 }
diff --git a/chromeos/components/tether/disconnect_tethering_operation.cc b/chromeos/components/tether/disconnect_tethering_operation.cc
index 5d4022d7..72c0a68 100644
--- a/chromeos/components/tether/disconnect_tethering_operation.cc
+++ b/chromeos/components/tether/disconnect_tethering_operation.cc
@@ -26,14 +26,12 @@
 DisconnectTetheringOperation::Factory::NewInstance(
     cryptauth::RemoteDeviceRef device_to_connect,
     device_sync::DeviceSyncClient* device_sync_client,
-    secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* connection_manager) {
+    secure_channel::SecureChannelClient* secure_channel_client) {
   if (!factory_instance_) {
     factory_instance_ = new Factory();
   }
   return factory_instance_->BuildInstance(device_to_connect, device_sync_client,
-                                          secure_channel_client,
-                                          connection_manager);
+                                          secure_channel_client);
 }
 
 // static
@@ -46,24 +44,20 @@
 DisconnectTetheringOperation::Factory::BuildInstance(
     cryptauth::RemoteDeviceRef device_to_connect,
     device_sync::DeviceSyncClient* device_sync_client,
-    secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* connection_manager) {
+    secure_channel::SecureChannelClient* secure_channel_client) {
   return base::WrapUnique(new DisconnectTetheringOperation(
-      device_to_connect, device_sync_client, secure_channel_client,
-      connection_manager));
+      device_to_connect, device_sync_client, secure_channel_client));
 }
 
 DisconnectTetheringOperation::DisconnectTetheringOperation(
     cryptauth::RemoteDeviceRef device_to_connect,
     device_sync::DeviceSyncClient* device_sync_client,
-    secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* connection_manager)
+    secure_channel::SecureChannelClient* secure_channel_client)
     : MessageTransferOperation(
           cryptauth::RemoteDeviceRefList{device_to_connect},
           secure_channel::ConnectionPriority::kHigh,
           device_sync_client,
-          secure_channel_client,
-          connection_manager),
+          secure_channel_client),
       remote_device_(device_to_connect),
       has_sent_message_(false),
       clock_(base::DefaultClock::GetInstance()) {}
diff --git a/chromeos/components/tether/disconnect_tethering_operation.h b/chromeos/components/tether/disconnect_tethering_operation.h
index 66cf883..ebc0d34 100644
--- a/chromeos/components/tether/disconnect_tethering_operation.h
+++ b/chromeos/components/tether/disconnect_tethering_operation.h
@@ -21,8 +21,6 @@
 
 namespace tether {
 
-class BleConnectionManager;
-
 // Operation which sends a disconnect message to a tether host.
 class DisconnectTetheringOperation : public MessageTransferOperation {
  public:
@@ -31,8 +29,7 @@
     static std::unique_ptr<DisconnectTetheringOperation> NewInstance(
         cryptauth::RemoteDeviceRef device_to_connect,
         device_sync::DeviceSyncClient* device_sync_client,
-        secure_channel::SecureChannelClient* secure_channel_client,
-        BleConnectionManager* connection_manager);
+        secure_channel::SecureChannelClient* secure_channel_client);
 
     static void SetInstanceForTesting(Factory* factory);
 
@@ -40,8 +37,7 @@
     virtual std::unique_ptr<DisconnectTetheringOperation> BuildInstance(
         cryptauth::RemoteDeviceRef device_to_connect,
         device_sync::DeviceSyncClient* device_sync_client,
-        secure_channel::SecureChannelClient* secure_channel_client,
-        BleConnectionManager* connection_manager);
+        secure_channel::SecureChannelClient* secure_channel_client);
 
    private:
     static Factory* factory_instance_;
@@ -65,8 +61,7 @@
   DisconnectTetheringOperation(
       cryptauth::RemoteDeviceRef device_to_connect,
       device_sync::DeviceSyncClient* device_sync_client,
-      secure_channel::SecureChannelClient* secure_channel_client,
-      BleConnectionManager* connection_manager);
+      secure_channel::SecureChannelClient* secure_channel_client);
 
   void NotifyObserversOperationFinished(bool success);
 
diff --git a/chromeos/components/tether/disconnect_tethering_operation_unittest.cc b/chromeos/components/tether/disconnect_tethering_operation_unittest.cc
index 3105ae7..e8b8fa6 100644
--- a/chromeos/components/tether/disconnect_tethering_operation_unittest.cc
+++ b/chromeos/components/tether/disconnect_tethering_operation_unittest.cc
@@ -79,7 +79,7 @@
 
     operation_ = base::WrapUnique(new DisconnectTetheringOperation(
         test_device_, fake_device_sync_client_.get(),
-        fake_secure_channel_client_.get(), fake_ble_connection_manager_.get()));
+        fake_secure_channel_client_.get()));
 
     test_observer_ = base::WrapUnique(new TestObserver());
     operation_->AddObserver(test_observer_.get());
diff --git a/chromeos/components/tether/disconnect_tethering_request_sender_impl.cc b/chromeos/components/tether/disconnect_tethering_request_sender_impl.cc
index 25b8c37..bf380f1 100644
--- a/chromeos/components/tether/disconnect_tethering_request_sender_impl.cc
+++ b/chromeos/components/tether/disconnect_tethering_request_sender_impl.cc
@@ -8,7 +8,6 @@
 
 #include "base/memory/ptr_util.h"
 #include "chromeos/components/proximity_auth/logging/logging.h"
-#include "chromeos/components/tether/ble_connection_manager.h"
 #include "chromeos/components/tether/tether_host_fetcher.h"
 
 namespace chromeos {
@@ -24,14 +23,12 @@
 DisconnectTetheringRequestSenderImpl::Factory::NewInstance(
     device_sync::DeviceSyncClient* device_sync_client,
     secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* ble_connection_manager,
     TetherHostFetcher* tether_host_fetcher) {
   if (!factory_instance_)
     factory_instance_ = new Factory();
 
   return factory_instance_->BuildInstance(
-      device_sync_client, secure_channel_client, ble_connection_manager,
-      tether_host_fetcher);
+      device_sync_client, secure_channel_client, tether_host_fetcher);
 }
 
 // static
@@ -44,21 +41,17 @@
 DisconnectTetheringRequestSenderImpl::Factory::BuildInstance(
     device_sync::DeviceSyncClient* device_sync_client,
     secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* ble_connection_manager,
     TetherHostFetcher* tether_host_fetcher) {
   return base::WrapUnique(new DisconnectTetheringRequestSenderImpl(
-      device_sync_client, secure_channel_client, ble_connection_manager,
-      tether_host_fetcher));
+      device_sync_client, secure_channel_client, tether_host_fetcher));
 }
 
 DisconnectTetheringRequestSenderImpl::DisconnectTetheringRequestSenderImpl(
     device_sync::DeviceSyncClient* device_sync_client,
     secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* ble_connection_manager,
     TetherHostFetcher* tether_host_fetcher)
     : device_sync_client_(device_sync_client),
       secure_channel_client_(secure_channel_client),
-      ble_connection_manager_(ble_connection_manager),
       tether_host_fetcher_(tether_host_fetcher),
       weak_ptr_factory_(this) {}
 
@@ -104,8 +97,7 @@
 
   std::unique_ptr<DisconnectTetheringOperation> disconnect_tethering_operation =
       DisconnectTetheringOperation::Factory::NewInstance(
-          *tether_host, device_sync_client_, secure_channel_client_,
-          ble_connection_manager_);
+          *tether_host, device_sync_client_, secure_channel_client_);
 
   // Add to the map.
   device_id_to_operation_map_.emplace(
diff --git a/chromeos/components/tether/disconnect_tethering_request_sender_impl.h b/chromeos/components/tether/disconnect_tethering_request_sender_impl.h
index abe7388..9eb9da7a 100644
--- a/chromeos/components/tether/disconnect_tethering_request_sender_impl.h
+++ b/chromeos/components/tether/disconnect_tethering_request_sender_impl.h
@@ -23,7 +23,6 @@
 
 namespace tether {
 
-class BleConnectionManager;
 class TetherHostFetcher;
 
 class DisconnectTetheringRequestSenderImpl
@@ -35,7 +34,6 @@
     static std::unique_ptr<DisconnectTetheringRequestSender> NewInstance(
         device_sync::DeviceSyncClient* device_sync_client,
         secure_channel::SecureChannelClient* secure_channel_client,
-        BleConnectionManager* ble_connection_manager,
         TetherHostFetcher* tether_host_fetcher);
 
     static void SetInstanceForTesting(Factory* factory);
@@ -44,7 +42,6 @@
     virtual std::unique_ptr<DisconnectTetheringRequestSender> BuildInstance(
         device_sync::DeviceSyncClient* device_sync_client,
         secure_channel::SecureChannelClient* secure_channel_client,
-        BleConnectionManager* ble_connection_manager,
         TetherHostFetcher* tether_host_fetcher);
 
    private:
@@ -64,7 +61,6 @@
   DisconnectTetheringRequestSenderImpl(
       device_sync::DeviceSyncClient* device_sync_client,
       secure_channel::SecureChannelClient* secure_channel_client,
-      BleConnectionManager* ble_connection_manager,
       TetherHostFetcher* tether_host_fetcher);
 
  private:
@@ -74,7 +70,6 @@
 
   device_sync::DeviceSyncClient* device_sync_client_;
   secure_channel::SecureChannelClient* secure_channel_client_;
-  BleConnectionManager* ble_connection_manager_;
   TetherHostFetcher* tether_host_fetcher_;
 
   int num_pending_host_fetches_ = 0;
diff --git a/chromeos/components/tether/disconnect_tethering_request_sender_impl_unittest.cc b/chromeos/components/tether/disconnect_tethering_request_sender_impl_unittest.cc
index f3ab490..ab14a01 100644
--- a/chromeos/components/tether/disconnect_tethering_request_sender_impl_unittest.cc
+++ b/chromeos/components/tether/disconnect_tethering_request_sender_impl_unittest.cc
@@ -12,7 +12,6 @@
 #include "chromeos/chromeos_features.h"
 #include "chromeos/components/tether/disconnect_tethering_operation.h"
 #include "chromeos/components/tether/disconnect_tethering_request_sender.h"
-#include "chromeos/components/tether/fake_ble_connection_manager.h"
 #include "chromeos/components/tether/fake_tether_host_fetcher.h"
 #include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "chromeos/services/secure_channel/public/cpp/client/fake_secure_channel_client.h"
@@ -31,12 +30,10 @@
   FakeDisconnectTetheringOperation(
       cryptauth::RemoteDeviceRef device_to_connect,
       device_sync::DeviceSyncClient* device_sync_client,
-      secure_channel::SecureChannelClient* secure_channel_client,
-      BleConnectionManager* connection_manager)
+      secure_channel::SecureChannelClient* secure_channel_client)
       : DisconnectTetheringOperation(device_to_connect,
                                      device_sync_client,
-                                     secure_channel_client,
-                                     connection_manager) {}
+                                     secure_channel_client) {}
 
   ~FakeDisconnectTetheringOperation() override = default;
 
@@ -65,12 +62,10 @@
   std::unique_ptr<DisconnectTetheringOperation> BuildInstance(
       cryptauth::RemoteDeviceRef device_to_connect,
       device_sync::DeviceSyncClient* device_sync_client,
-      secure_channel::SecureChannelClient* secure_channel_client,
-      BleConnectionManager* connection_manager) override {
+      secure_channel::SecureChannelClient* secure_channel_client) override {
     FakeDisconnectTetheringOperation* operation =
         new FakeDisconnectTetheringOperation(
-            device_to_connect, device_sync_client, secure_channel_client,
-            connection_manager);
+            device_to_connect, device_sync_client, secure_channel_client);
     created_operations_.push_back(operation);
     return base::WrapUnique(operation);
   }
@@ -114,7 +109,6 @@
         std::make_unique<device_sync::FakeDeviceSyncClient>();
     fake_secure_channel_client_ =
         std::make_unique<secure_channel::FakeSecureChannelClient>();
-    fake_ble_connection_manager_ = std::make_unique<FakeBleConnectionManager>();
     fake_tether_host_fetcher_ =
         std::make_unique<FakeTetherHostFetcher>(test_devices_);
 
@@ -126,7 +120,6 @@
     disconnect_tethering_request_sender_ =
         DisconnectTetheringRequestSenderImpl::Factory::NewInstance(
             fake_device_sync_client_.get(), fake_secure_channel_client_.get(),
-            fake_ble_connection_manager_.get(),
             fake_tether_host_fetcher_.get());
 
     fake_disconnect_tethering_request_sender_observer_ =
@@ -199,7 +192,6 @@
   std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_;
   std::unique_ptr<secure_channel::SecureChannelClient>
       fake_secure_channel_client_;
-  std::unique_ptr<FakeBleConnectionManager> fake_ble_connection_manager_;
   std::unique_ptr<FakeTetherHostFetcher> fake_tether_host_fetcher_;
 
   std::unique_ptr<FakeDisconnectTetheringOperationFactory>
diff --git a/chromeos/components/tether/fake_asynchronous_shutdown_object_container.cc b/chromeos/components/tether/fake_asynchronous_shutdown_object_container.cc
index 56c9b1d..2465767 100644
--- a/chromeos/components/tether/fake_asynchronous_shutdown_object_container.cc
+++ b/chromeos/components/tether/fake_asynchronous_shutdown_object_container.cc
@@ -28,11 +28,6 @@
   return tether_host_fetcher_;
 }
 
-BleConnectionManager*
-FakeAsynchronousShutdownObjectContainer::ble_connection_manager() {
-  return ble_connection_manager_;
-}
-
 DisconnectTetheringRequestSender*
 FakeAsynchronousShutdownObjectContainer::disconnect_tethering_request_sender() {
   return disconnect_tethering_request_sender_;
diff --git a/chromeos/components/tether/fake_asynchronous_shutdown_object_container.h b/chromeos/components/tether/fake_asynchronous_shutdown_object_container.h
index 157c5bf5..91b56b9 100644
--- a/chromeos/components/tether/fake_asynchronous_shutdown_object_container.h
+++ b/chromeos/components/tether/fake_asynchronous_shutdown_object_container.h
@@ -32,11 +32,6 @@
     tether_host_fetcher_ = tether_host_fetcher;
   }
 
-  void set_ble_connection_manager(
-      BleConnectionManager* ble_connection_manager) {
-    ble_connection_manager_ = ble_connection_manager;
-  }
-
   void set_disconnect_tethering_request_sender(
       DisconnectTetheringRequestSender* disconnect_tethering_request_sender) {
     disconnect_tethering_request_sender_ = disconnect_tethering_request_sender;
@@ -55,7 +50,6 @@
   // AsynchronousShutdownObjectContainer:
   void Shutdown(const base::Closure& shutdown_complete_callback) override;
   TetherHostFetcher* tether_host_fetcher() override;
-  BleConnectionManager* ble_connection_manager() override;
   DisconnectTetheringRequestSender* disconnect_tethering_request_sender()
       override;
   NetworkConfigurationRemover* network_configuration_remover() override;
@@ -66,7 +60,6 @@
   base::Closure shutdown_complete_callback_;
 
   TetherHostFetcher* tether_host_fetcher_ = nullptr;
-  BleConnectionManager* ble_connection_manager_ = nullptr;
   DisconnectTetheringRequestSender* disconnect_tethering_request_sender_ =
       nullptr;
   NetworkConfigurationRemover* network_configuration_remover_ = nullptr;
diff --git a/chromeos/components/tether/host_connection_metrics_logger.cc b/chromeos/components/tether/host_connection_metrics_logger.cc
index 575878f..b847db3b 100644
--- a/chromeos/components/tether/host_connection_metrics_logger.cc
+++ b/chromeos/components/tether/host_connection_metrics_logger.cc
@@ -6,26 +6,18 @@
 
 #include "base/metrics/histogram_macros.h"
 #include "base/time/default_clock.h"
-#include "chromeos/chromeos_features.h"
 
 namespace chromeos {
 
 namespace tether {
 
 HostConnectionMetricsLogger::HostConnectionMetricsLogger(
-    BleConnectionManager* connection_manager,
     ActiveHost* active_host)
-    : connection_manager_(connection_manager),
-      active_host_(active_host),
-      clock_(base::DefaultClock::GetInstance()) {
-  if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi))
-    connection_manager_->AddMetricsObserver(this);
+    : active_host_(active_host), clock_(base::DefaultClock::GetInstance()) {
   active_host_->AddObserver(this);
 }
 
 HostConnectionMetricsLogger::~HostConnectionMetricsLogger() {
-  if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi))
-    connection_manager_->RemoveMetricsObserver(this);
   active_host_->RemoveObserver(this);
 }
 
@@ -112,15 +104,6 @@
   };
 }
 
-void HostConnectionMetricsLogger::OnAdvertisementReceived(
-    const std::string& device_id,
-    bool is_background_advertisement) {
-  DCHECK(!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi));
-
-  device_id_to_received_background_advertisement_[device_id] =
-      is_background_advertisement;
-}
-
 void HostConnectionMetricsLogger::OnActiveHostChanged(
     const ActiveHost::ActiveHostChangeInfo& change_info) {
   if (change_info.new_status == ActiveHost::ActiveHostStatus::CONNECTING) {
@@ -144,20 +127,11 @@
     ConnectionToHostResult_SuccessEventType event_type) {
   DCHECK(!active_host_device_id_.empty());
 
-  bool is_background_advertisement =
-      device_id_to_received_background_advertisement_[active_host_device_id_];
   active_host_device_id_.clear();
 
-  if (is_background_advertisement ||
-      base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
-    UMA_HISTOGRAM_ENUMERATION(
-        "InstantTethering.ConnectionToHostResult.SuccessRate.Background",
-        event_type, ConnectionToHostResult_SuccessEventType::SUCCESS_MAX);
-  } else {
-    UMA_HISTOGRAM_ENUMERATION(
-        "InstantTethering.ConnectionToHostResult.SuccessRate", event_type,
-        ConnectionToHostResult_SuccessEventType::SUCCESS_MAX);
-  }
+  UMA_HISTOGRAM_ENUMERATION(
+      "InstantTethering.ConnectionToHostResult.SuccessRate.Background",
+      event_type, ConnectionToHostResult_SuccessEventType::SUCCESS_MAX);
 
   RecordConnectionResultProvisioningFailure(
       ConnectionToHostResult_ProvisioningFailureEventType::OTHER);
@@ -201,23 +175,13 @@
     const std::string device_id) {
   DCHECK(!connect_to_host_start_time_.is_null());
 
-  bool is_background_advertisement =
-      device_id_to_received_background_advertisement_[device_id];
-
   base::TimeDelta connect_to_host_duration =
       clock_->Now() - connect_to_host_start_time_;
   connect_to_host_start_time_ = base::Time();
 
-  if (is_background_advertisement ||
-      base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
-    UMA_HISTOGRAM_MEDIUM_TIMES(
-        "InstantTethering.Performance.ConnectToHostDuration.Background",
-        connect_to_host_duration);
-  } else {
-    UMA_HISTOGRAM_MEDIUM_TIMES(
-        "InstantTethering.Performance.ConnectToHostDuration",
-        connect_to_host_duration);
-  }
+  UMA_HISTOGRAM_MEDIUM_TIMES(
+      "InstantTethering.Performance.ConnectToHostDuration.Background",
+      connect_to_host_duration);
 }
 
 void HostConnectionMetricsLogger::SetClockForTesting(base::Clock* test_clock) {
diff --git a/chromeos/components/tether/host_connection_metrics_logger.h b/chromeos/components/tether/host_connection_metrics_logger.h
index 6204c63..44af3e58 100644
--- a/chromeos/components/tether/host_connection_metrics_logger.h
+++ b/chromeos/components/tether/host_connection_metrics_logger.h
@@ -11,7 +11,6 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "chromeos/components/tether/active_host.h"
-#include "chromeos/components/tether/ble_connection_manager.h"
 
 namespace base {
 class Clock;
@@ -24,9 +23,7 @@
 // Wrapper around metrics reporting for host connection results. Clients are
 // expected to report the result of a host connection attempt once it has
 // concluded.
-class HostConnectionMetricsLogger
-    : public BleConnectionManager::MetricsObserver,
-      public ActiveHost::Observer {
+class HostConnectionMetricsLogger : public ActiveHost::Observer {
  public:
   enum ConnectionToHostResult {
     CONNECTION_RESULT_PROVISIONING_FAILED,
@@ -49,15 +46,10 @@
   virtual void RecordConnectionToHostResult(ConnectionToHostResult result,
                                             const std::string& device_id);
 
-  HostConnectionMetricsLogger(BleConnectionManager* connection_manager,
-                              ActiveHost* active_host);
+  HostConnectionMetricsLogger(ActiveHost* active_host);
   virtual ~HostConnectionMetricsLogger();
 
  protected:
-  // BleConnectionManager::MetricsObserver:
-  void OnAdvertisementReceived(const std::string& device_id,
-                               bool is_background_advertisement) override;
-
   // ActiveHost::Observer:
   void OnActiveHostChanged(
       const ActiveHost::ActiveHostChangeInfo& change_info) override;
@@ -201,11 +193,9 @@
 
   void SetClockForTesting(base::Clock* test_clock);
 
-  BleConnectionManager* connection_manager_;
   ActiveHost* active_host_;
   base::Clock* clock_;
 
-  std::map<std::string, bool> device_id_to_received_background_advertisement_;
   base::Time connect_to_host_start_time_;
   std::string active_host_device_id_;
 
diff --git a/chromeos/components/tether/host_connection_metrics_logger_unittest.cc b/chromeos/components/tether/host_connection_metrics_logger_unittest.cc
index 742f969..c19af5d 100644
--- a/chromeos/components/tether/host_connection_metrics_logger_unittest.cc
+++ b/chromeos/components/tether/host_connection_metrics_logger_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/test/simple_test_clock.h"
 #include "chromeos/chromeos_features.h"
 #include "chromeos/components/tether/fake_active_host.h"
-#include "chromeos/components/tether/fake_ble_connection_manager.h"
 #include "components/cryptauth/remote_device_ref.h"
 #include "components/cryptauth/remote_device_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -32,20 +31,15 @@
       : test_devices_(cryptauth::CreateRemoteDeviceRefListForTest(2u)) {}
 
   void SetUp() override {
-    fake_ble_connection_manager_ = std::make_unique<FakeBleConnectionManager>();
     fake_active_host_ = std::make_unique<FakeActiveHost>();
 
-    metrics_logger_ = std::make_unique<HostConnectionMetricsLogger>(
-        fake_ble_connection_manager_.get(), fake_active_host_.get());
+    metrics_logger_ =
+        std::make_unique<HostConnectionMetricsLogger>(fake_active_host_.get());
 
     test_clock_.SetNow(base::Time::UnixEpoch());
     metrics_logger_->SetClockForTesting(&test_clock_);
   }
 
-  void SetMultiDeviceApiDisabled() {
-    scoped_feature_list_.InitAndDisableFeature(features::kMultiDeviceApi);
-  }
-
   void VerifyProvisioningFailure(
       HostConnectionMetricsLogger::
           ConnectionToHostResult_ProvisioningFailureEventType event_type) {
@@ -93,13 +87,7 @@
 
   void VerifyConnectToHostDuration(bool is_background_advertisement) {
     std::string device_id = test_devices_[0].GetDeviceId();
-
-    if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
-      SetActiveHostToConnecting(device_id);
-    } else {
-      SetActiveHostToConnectingAndReceiveAdvertisement(
-          device_id, is_background_advertisement);
-    }
+    SetActiveHostToConnecting(device_id);
 
     test_clock_.Advance(kConnectToHostTime);
 
@@ -117,22 +105,12 @@
     }
   }
 
-  void SetActiveHostToConnectingAndReceiveAdvertisement(
-      const std::string& device_id,
-      bool is_background_advertisement) {
-    fake_ble_connection_manager_->NotifyAdvertisementReceived(
-        device_id, is_background_advertisement);
-
-    fake_active_host_->SetActiveHostConnecting(device_id, kTetherNetworkGuid);
-  }
-
   void SetActiveHostToConnecting(const std::string& device_id) {
     fake_active_host_->SetActiveHostConnecting(device_id, kTetherNetworkGuid);
   }
 
   const cryptauth::RemoteDeviceRefList test_devices_;
 
-  std::unique_ptr<FakeBleConnectionManager> fake_ble_connection_manager_;
   std::unique_ptr<FakeActiveHost> fake_active_host_;
   std::unique_ptr<HostConnectionMetricsLogger> metrics_logger_;
 
@@ -147,10 +125,7 @@
 
 TEST_F(HostConnectionMetricsLoggerTest,
        RecordConnectionResultProvisioningFailure) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), false /* is_background_advertisement */);
+  SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
       HostConnectionMetricsLogger::ConnectionToHostResult::
@@ -164,44 +139,6 @@
 }
 
 TEST_F(HostConnectionMetricsLoggerTest, RecordConnectionResultSuccess) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), false /* is_background_advertisement */);
-
-  metrics_logger_->RecordConnectionToHostResult(
-      HostConnectionMetricsLogger::ConnectionToHostResult::
-          CONNECTION_RESULT_SUCCESS,
-      test_devices_[0].GetDeviceId());
-
-  VerifySuccess(HostConnectionMetricsLogger::
-                    ConnectionToHostResult_SuccessEventType::SUCCESS,
-                false /* is_background_advertisement */);
-  VerifyProvisioningFailure(
-      HostConnectionMetricsLogger::
-          ConnectionToHostResult_ProvisioningFailureEventType::OTHER);
-}
-
-TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultSuccess_Background) {
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), true /* is_background_advertisement */);
-
-  metrics_logger_->RecordConnectionToHostResult(
-      HostConnectionMetricsLogger::ConnectionToHostResult::
-          CONNECTION_RESULT_SUCCESS,
-      test_devices_[0].GetDeviceId());
-
-  VerifySuccess(HostConnectionMetricsLogger::
-                    ConnectionToHostResult_SuccessEventType::SUCCESS,
-                true /* is_background_advertisement */);
-  VerifyProvisioningFailure(
-      HostConnectionMetricsLogger::
-          ConnectionToHostResult_ProvisioningFailureEventType::OTHER);
-}
-
-TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultSuccess_MultiDeviceApiEnabled) {
   SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
@@ -218,11 +155,8 @@
 }
 
 TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultSuccess_Background_DifferentDevice) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), true /* is_background_advertisement */);
+       DISABLED_RecordConnectionResultSuccess_Background_DifferentDevice) {
+  SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
       HostConnectionMetricsLogger::ConnectionToHostResult::
@@ -238,50 +172,6 @@
 }
 
 TEST_F(HostConnectionMetricsLoggerTest, RecordConnectionResultFailure) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), false /* is_background_advertisement */);
-
-  metrics_logger_->RecordConnectionToHostResult(
-      HostConnectionMetricsLogger::ConnectionToHostResult::
-          CONNECTION_RESULT_FAILURE_UNKNOWN_ERROR,
-      test_devices_[0].GetDeviceId());
-
-  VerifyFailure(HostConnectionMetricsLogger::
-                    ConnectionToHostResult_FailureEventType::UNKNOWN_ERROR);
-
-  VerifySuccess(HostConnectionMetricsLogger::
-                    ConnectionToHostResult_SuccessEventType::FAILURE,
-                false /* is_background_advertisement */);
-  VerifyProvisioningFailure(
-      HostConnectionMetricsLogger::
-          ConnectionToHostResult_ProvisioningFailureEventType::OTHER);
-}
-
-TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultFailure_Background) {
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), true /* is_background_advertisement */);
-
-  metrics_logger_->RecordConnectionToHostResult(
-      HostConnectionMetricsLogger::ConnectionToHostResult::
-          CONNECTION_RESULT_FAILURE_UNKNOWN_ERROR,
-      test_devices_[0].GetDeviceId());
-
-  VerifyFailure(HostConnectionMetricsLogger::
-                    ConnectionToHostResult_FailureEventType::UNKNOWN_ERROR);
-
-  VerifySuccess(HostConnectionMetricsLogger::
-                    ConnectionToHostResult_SuccessEventType::FAILURE,
-                true /* is_background_advertisement */);
-  VerifyProvisioningFailure(
-      HostConnectionMetricsLogger::
-          ConnectionToHostResult_ProvisioningFailureEventType::OTHER);
-}
-
-TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultFailure_MultiDeviceApiEnabled) {
   SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
@@ -301,11 +191,8 @@
 }
 
 TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultFailure_Background_DifferentDevice) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), true /* is_background_advertisement */);
+       DISABLED_RecordConnectionResultFailure_Background_DifferentDevice) {
+  SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
       HostConnectionMetricsLogger::ConnectionToHostResult::
@@ -324,11 +211,8 @@
 }
 
 TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultFailureClientConnection_Timeout) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), false /* is_background_advertisement */);
+       DISABLED_RecordConnectionResultFailureClientConnection_Timeout) {
+  SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
       HostConnectionMetricsLogger::ConnectionToHostResult::
@@ -350,11 +234,8 @@
 }
 
 TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultFailureClientConnection_CanceledByUser) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), false /* is_background_advertisement */);
+       DISABLED_RecordConnectionResultFailureClientConnection_CanceledByUser) {
+  SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
       HostConnectionMetricsLogger::ConnectionToHostResult::
@@ -377,11 +258,8 @@
 }
 
 TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultFailureClientConnection_InternalError) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), false /* is_background_advertisement */);
+       DISABLED_RecordConnectionResultFailureClientConnection_InternalError) {
+  SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
       HostConnectionMetricsLogger::ConnectionToHostResult::
@@ -404,11 +282,8 @@
 }
 
 TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultFailureTetheringTimeout_SetupRequired) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), false /* is_background_advertisement */);
+       DISABLED_RecordConnectionResultFailureTetheringTimeout_SetupRequired) {
+  SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
       HostConnectionMetricsLogger::ConnectionToHostResult::
@@ -430,12 +305,10 @@
           ConnectionToHostResult_ProvisioningFailureEventType::OTHER);
 }
 
-TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultFailureTetheringTimeout_SetupNotRequired) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), false /* is_background_advertisement */);
+TEST_F(
+    HostConnectionMetricsLoggerTest,
+    DISABLED_RecordConnectionResultFailureTetheringTimeout_SetupNotRequired) {
+  SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
       HostConnectionMetricsLogger::ConnectionToHostResult::
@@ -458,11 +331,8 @@
 }
 
 TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultFailureTetheringUnsupported) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), false /* is_background_advertisement */);
+       DISABLED_RecordConnectionResultFailureTetheringUnsupported) {
+  SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
       HostConnectionMetricsLogger::ConnectionToHostResult::
@@ -478,11 +348,8 @@
 }
 
 TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultFailureNoCellData) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), false /* is_background_advertisement */);
+       DISABLED_RecordConnectionResultFailureNoCellData) {
+  SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
       HostConnectionMetricsLogger::ConnectionToHostResult::
@@ -497,11 +364,8 @@
 }
 
 TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultFailureEnablingHotspotFailed) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), false /* is_background_advertisement */);
+       DISABLED_RecordConnectionResultFailureEnablingHotspotFailed) {
+  SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
       HostConnectionMetricsLogger::ConnectionToHostResult::
@@ -517,11 +381,8 @@
 }
 
 TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultFailureEnablingHotspotTimeout) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), false /* is_background_advertisement */);
+       DISABLED_RecordConnectionResultFailureEnablingHotspotTimeout) {
+  SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
       HostConnectionMetricsLogger::ConnectionToHostResult::
@@ -537,27 +398,12 @@
 }
 
 TEST_F(HostConnectionMetricsLoggerTest, RecordConnectToHostDuration) {
-  SetMultiDeviceApiDisabled();
-
-  VerifyConnectToHostDuration(false /* is_background_advertisement */);
-}
-
-TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectToHostDuration_Background) {
   VerifyConnectToHostDuration(true /* is_background_advertisement */);
 }
 
 TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectToHostDuration_MultiDeviceApiEnabled) {
-  VerifyConnectToHostDuration(true /* is_background_advertisement */);
-}
-
-TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultFailureNoResponse) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), false /* is_background_advertisement */);
+       DISABLED_RecordConnectionResultFailureNoResponse) {
+  SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
       HostConnectionMetricsLogger::ConnectionToHostResult::
@@ -572,11 +418,8 @@
 }
 
 TEST_F(HostConnectionMetricsLoggerTest,
-       RecordConnectionResultFailureInvalidHotspotCredentials) {
-  SetMultiDeviceApiDisabled();
-
-  SetActiveHostToConnectingAndReceiveAdvertisement(
-      test_devices_[0].GetDeviceId(), false /* is_background_advertisement */);
+       DISABLED_RecordConnectionResultFailureInvalidHotspotCredentials) {
+  SetActiveHostToConnecting(test_devices_[0].GetDeviceId());
 
   metrics_logger_->RecordConnectionToHostResult(
       HostConnectionMetricsLogger::ConnectionToHostResult::
diff --git a/chromeos/components/tether/host_scanner_impl.cc b/chromeos/components/tether/host_scanner_impl.cc
index 001c0aee..b321770c 100644
--- a/chromeos/components/tether/host_scanner_impl.cc
+++ b/chromeos/components/tether/host_scanner_impl.cc
@@ -30,7 +30,6 @@
     NetworkStateHandler* network_state_handler,
     session_manager::SessionManager* session_manager,
     TetherHostFetcher* tether_host_fetcher,
-    BleConnectionManager* connection_manager,
     HostScanDevicePrioritizer* host_scan_device_prioritizer,
     TetherHostResponseRecorder* tether_host_response_recorder,
     GmsCoreNotificationsStateTrackerImpl* gms_core_notifications_state_tracker,
@@ -44,7 +43,6 @@
       network_state_handler_(network_state_handler),
       session_manager_(session_manager),
       tether_host_fetcher_(tether_host_fetcher),
-      connection_manager_(connection_manager),
       host_scan_device_prioritizer_(host_scan_device_prioritizer),
       tether_host_response_recorder_(tether_host_response_recorder),
       gms_core_notifications_state_tracker_(
@@ -106,8 +104,8 @@
 
   host_scanner_operation_ = HostScannerOperation::Factory::NewInstance(
       tether_hosts, device_sync_client_, secure_channel_client_,
-      connection_manager_, host_scan_device_prioritizer_,
-      tether_host_response_recorder_, connection_preserver_);
+      host_scan_device_prioritizer_, tether_host_response_recorder_,
+      connection_preserver_);
   // Add |gms_core_notifications_state_tracker_| as the first observer. When the
   // final change event is emitted, this class will destroy
   // |host_scanner_operation_|, so |gms_core_notifications_state_tracker_| must
diff --git a/chromeos/components/tether/host_scanner_impl.h b/chromeos/components/tether/host_scanner_impl.h
index e0d89ac..18f4ad2 100644
--- a/chromeos/components/tether/host_scanner_impl.h
+++ b/chromeos/components/tether/host_scanner_impl.h
@@ -38,7 +38,6 @@
 
 namespace tether {
 
-class BleConnectionManager;
 class ConnectionPreserver;
 class DeviceIdTetherNetworkGuidMap;
 class GmsCoreNotificationsStateTrackerImpl;
@@ -67,7 +66,6 @@
       NetworkStateHandler* network_state_handler,
       session_manager::SessionManager* session_manager,
       TetherHostFetcher* tether_host_fetcher,
-      BleConnectionManager* connection_manager,
       HostScanDevicePrioritizer* host_scan_device_prioritizer,
       TetherHostResponseRecorder* tether_host_response_recorder,
       GmsCoreNotificationsStateTrackerImpl*
@@ -123,7 +121,6 @@
   NetworkStateHandler* network_state_handler_;
   session_manager::SessionManager* session_manager_;
   TetherHostFetcher* tether_host_fetcher_;
-  BleConnectionManager* connection_manager_;
   HostScanDevicePrioritizer* host_scan_device_prioritizer_;
   TetherHostResponseRecorder* tether_host_response_recorder_;
   GmsCoreNotificationsStateTrackerImpl* gms_core_notifications_state_tracker_;
diff --git a/chromeos/components/tether/host_scanner_impl_unittest.cc b/chromeos/components/tether/host_scanner_impl_unittest.cc
index 5d9ea8be..c8323aa9 100644
--- a/chromeos/components/tether/host_scanner_impl_unittest.cc
+++ b/chromeos/components/tether/host_scanner_impl_unittest.cc
@@ -17,7 +17,6 @@
 #include "base/time/time.h"
 #include "chromeos/chromeos_features.h"
 #include "chromeos/components/tether/device_id_tether_network_guid_map.h"
-#include "chromeos/components/tether/fake_ble_connection_manager.h"
 #include "chromeos/components/tether/fake_connection_preserver.h"
 #include "chromeos/components/tether/fake_host_scan_cache.h"
 #include "chromeos/components/tether/fake_notification_presenter.h"
@@ -70,14 +69,12 @@
       const cryptauth::RemoteDeviceRefList& devices_to_connect,
       device_sync::DeviceSyncClient* device_sync_client,
       secure_channel::SecureChannelClient* secure_channel_client,
-      BleConnectionManager* connection_manager,
       HostScanDevicePrioritizer* host_scan_device_prioritizer,
       TetherHostResponseRecorder* tether_host_response_recorder,
       ConnectionPreserver* connection_preserver)
       : HostScannerOperation(devices_to_connect,
                              device_sync_client,
                              secure_channel_client,
-                             connection_manager,
                              host_scan_device_prioritizer,
                              tether_host_response_recorder,
                              connection_preserver) {}
@@ -110,15 +107,14 @@
       const cryptauth::RemoteDeviceRefList& devices_to_connect,
       device_sync::DeviceSyncClient* device_sync_client,
       secure_channel::SecureChannelClient* secure_channel_client,
-      BleConnectionManager* connection_manager,
       HostScanDevicePrioritizer* host_scan_device_prioritizer,
       TetherHostResponseRecorder* tether_host_response_recorder,
       ConnectionPreserver* connection_preserver) override {
     EXPECT_EQ(expected_devices_, devices_to_connect);
     FakeHostScannerOperation* operation = new FakeHostScannerOperation(
         devices_to_connect, device_sync_client, secure_channel_client,
-        connection_manager, host_scan_device_prioritizer,
-        tether_host_response_recorder, connection_preserver);
+        host_scan_device_prioritizer, tether_host_response_recorder,
+        connection_preserver);
     created_operations_.push_back(operation);
     return base::WrapUnique(operation);
   }
@@ -221,7 +217,6 @@
     session_manager_ = std::make_unique<session_manager::SessionManager>();
     fake_tether_host_fetcher_ =
         std::make_unique<FakeTetherHostFetcher>(test_devices_);
-    fake_ble_connection_manager_ = std::make_unique<FakeBleConnectionManager>();
     fake_host_scan_device_prioritizer_ =
         std::make_unique<FakeHostScanDevicePrioritizer>();
     mock_tether_host_response_recorder_ =
@@ -246,7 +241,7 @@
     host_scanner_ = base::WrapUnique(new HostScannerImpl(
         fake_device_sync_client_.get(), fake_secure_channel_client_.get(),
         network_state_handler(), session_manager_.get(),
-        fake_tether_host_fetcher_.get(), fake_ble_connection_manager_.get(),
+        fake_tether_host_fetcher_.get(),
         fake_host_scan_device_prioritizer_.get(),
         mock_tether_host_response_recorder_.get(),
         gms_core_notifications_state_tracker_.get(),
@@ -419,7 +414,6 @@
       fake_secure_channel_client_;
   std::unique_ptr<session_manager::SessionManager> session_manager_;
   std::unique_ptr<FakeTetherHostFetcher> fake_tether_host_fetcher_;
-  std::unique_ptr<FakeBleConnectionManager> fake_ble_connection_manager_;
   std::unique_ptr<HostScanDevicePrioritizer> fake_host_scan_device_prioritizer_;
   std::unique_ptr<MockTetherHostResponseRecorder>
       mock_tether_host_response_recorder_;
diff --git a/chromeos/components/tether/host_scanner_operation.cc b/chromeos/components/tether/host_scanner_operation.cc
index 535bf8d1..06e2997 100644
--- a/chromeos/components/tether/host_scanner_operation.cc
+++ b/chromeos/components/tether/host_scanner_operation.cc
@@ -85,7 +85,6 @@
     const cryptauth::RemoteDeviceRefList& devices_to_connect,
     device_sync::DeviceSyncClient* device_sync_client,
     secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* connection_manager,
     HostScanDevicePrioritizer* host_scan_device_prioritizer,
     TetherHostResponseRecorder* tether_host_response_recorder,
     ConnectionPreserver* connection_preserver) {
@@ -94,8 +93,8 @@
   }
   return factory_instance_->BuildInstance(
       devices_to_connect, device_sync_client, secure_channel_client,
-      connection_manager, host_scan_device_prioritizer,
-      tether_host_response_recorder, connection_preserver);
+      host_scan_device_prioritizer, tether_host_response_recorder,
+      connection_preserver);
 }
 
 // static
@@ -108,14 +107,13 @@
     const cryptauth::RemoteDeviceRefList& devices_to_connect,
     device_sync::DeviceSyncClient* device_sync_client,
     secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* connection_manager,
     HostScanDevicePrioritizer* host_scan_device_prioritizer,
     TetherHostResponseRecorder* tether_host_response_recorder,
     ConnectionPreserver* connection_preserver) {
   return base::WrapUnique(new HostScannerOperation(
       devices_to_connect, device_sync_client, secure_channel_client,
-      connection_manager, host_scan_device_prioritizer,
-      tether_host_response_recorder, connection_preserver));
+      host_scan_device_prioritizer, tether_host_response_recorder,
+      connection_preserver));
 }
 
 HostScannerOperation::ScannedDeviceInfo::ScannedDeviceInfo(
@@ -140,7 +138,6 @@
     const cryptauth::RemoteDeviceRefList& devices_to_connect,
     device_sync::DeviceSyncClient* device_sync_client,
     secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* connection_manager,
     HostScanDevicePrioritizer* host_scan_device_prioritizer,
     TetherHostResponseRecorder* tether_host_response_recorder,
     ConnectionPreserver* connection_preserver)
@@ -148,8 +145,7 @@
           PrioritizeDevices(devices_to_connect, host_scan_device_prioritizer),
           secure_channel::ConnectionPriority::kLow,
           device_sync_client,
-          secure_channel_client,
-          connection_manager),
+          secure_channel_client),
       tether_host_response_recorder_(tether_host_response_recorder),
       connection_preserver_(connection_preserver),
       clock_(base::DefaultClock::GetInstance()),
diff --git a/chromeos/components/tether/host_scanner_operation.h b/chromeos/components/tether/host_scanner_operation.h
index 4e5402f..28d7326 100644
--- a/chromeos/components/tether/host_scanner_operation.h
+++ b/chromeos/components/tether/host_scanner_operation.h
@@ -11,7 +11,6 @@
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/time/clock.h"
-#include "chromeos/components/tether/ble_connection_manager.h"
 #include "chromeos/components/tether/message_transfer_operation.h"
 #include "components/cryptauth/remote_device_ref.h"
 
@@ -45,7 +44,6 @@
         const cryptauth::RemoteDeviceRefList& devices_to_connect,
         device_sync::DeviceSyncClient* device_sync_client,
         secure_channel::SecureChannelClient* secure_channel_client,
-        BleConnectionManager* connection_manager,
         HostScanDevicePrioritizer* host_scan_device_prioritizer,
         TetherHostResponseRecorder* tether_host_response_recorder,
         ConnectionPreserver* connection_preserver);
@@ -57,7 +55,6 @@
         const cryptauth::RemoteDeviceRefList& devices_to_connect,
         device_sync::DeviceSyncClient* device_sync_client,
         secure_channel::SecureChannelClient* secure_channel_client,
-        BleConnectionManager* connection_manager,
         HostScanDevicePrioritizer* host_scan_device_prioritizer,
         TetherHostResponseRecorder* tether_host_response_recorder,
         ConnectionPreserver* connection_preserver);
@@ -103,7 +100,6 @@
       const cryptauth::RemoteDeviceRefList& devices_to_connect,
       device_sync::DeviceSyncClient* device_sync_client,
       secure_channel::SecureChannelClient* secure_channel_client,
-      BleConnectionManager* connection_manager,
       HostScanDevicePrioritizer* host_scan_device_prioritizer,
       TetherHostResponseRecorder* tether_host_response_recorder,
       ConnectionPreserver* connection_preserver);
diff --git a/chromeos/components/tether/host_scanner_operation_unittest.cc b/chromeos/components/tether/host_scanner_operation_unittest.cc
index cf126c6b..15d6b5f 100644
--- a/chromeos/components/tether/host_scanner_operation_unittest.cc
+++ b/chromeos/components/tether/host_scanner_operation_unittest.cc
@@ -155,12 +155,12 @@
 
   void ConstructOperation(
       const cryptauth::RemoteDeviceRefList& remote_devices) {
-    operation_ = base::WrapUnique(new HostScannerOperation(
-        remote_devices, fake_device_sync_client_.get(),
-        fake_secure_channel_client_.get(), fake_ble_connection_manager_.get(),
-        test_host_scan_device_prioritizer_.get(),
-        mock_tether_host_response_recorder_.get(),
-        fake_connection_preserver_.get()));
+    operation_ = base::WrapUnique(
+        new HostScannerOperation(remote_devices, fake_device_sync_client_.get(),
+                                 fake_secure_channel_client_.get(),
+                                 test_host_scan_device_prioritizer_.get(),
+                                 mock_tether_host_response_recorder_.get(),
+                                 fake_connection_preserver_.get()));
     operation_->AddObserver(test_observer_.get());
 
     // Verify that the devices have been correctly prioritized.
diff --git a/chromeos/components/tether/keep_alive_operation.cc b/chromeos/components/tether/keep_alive_operation.cc
index 0b0b9e1..04bafab 100644
--- a/chromeos/components/tether/keep_alive_operation.cc
+++ b/chromeos/components/tether/keep_alive_operation.cc
@@ -23,14 +23,12 @@
 std::unique_ptr<KeepAliveOperation> KeepAliveOperation::Factory::NewInstance(
     cryptauth::RemoteDeviceRef device_to_connect,
     device_sync::DeviceSyncClient* device_sync_client,
-    secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* connection_manager) {
+    secure_channel::SecureChannelClient* secure_channel_client) {
   if (!factory_instance_) {
     factory_instance_ = new Factory();
   }
   return factory_instance_->BuildInstance(device_to_connect, device_sync_client,
-                                          secure_channel_client,
-                                          connection_manager);
+                                          secure_channel_client);
 }
 
 // static
@@ -41,24 +39,20 @@
 std::unique_ptr<KeepAliveOperation> KeepAliveOperation::Factory::BuildInstance(
     cryptauth::RemoteDeviceRef device_to_connect,
     device_sync::DeviceSyncClient* device_sync_client,
-    secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* connection_manager) {
-  return base::WrapUnique(
-      new KeepAliveOperation(device_to_connect, device_sync_client,
-                             secure_channel_client, connection_manager));
+    secure_channel::SecureChannelClient* secure_channel_client) {
+  return base::WrapUnique(new KeepAliveOperation(
+      device_to_connect, device_sync_client, secure_channel_client));
 }
 
 KeepAliveOperation::KeepAliveOperation(
     cryptauth::RemoteDeviceRef device_to_connect,
     device_sync::DeviceSyncClient* device_sync_client,
-    secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* connection_manager)
+    secure_channel::SecureChannelClient* secure_channel_client)
     : MessageTransferOperation(
           cryptauth::RemoteDeviceRefList{device_to_connect},
           secure_channel::ConnectionPriority::kMedium,
           device_sync_client,
-          secure_channel_client,
-          connection_manager),
+          secure_channel_client),
       remote_device_(device_to_connect),
       clock_(base::DefaultClock::GetInstance()) {}
 
diff --git a/chromeos/components/tether/keep_alive_operation.h b/chromeos/components/tether/keep_alive_operation.h
index 6bf05e9..d8570c0 100644
--- a/chromeos/components/tether/keep_alive_operation.h
+++ b/chromeos/components/tether/keep_alive_operation.h
@@ -21,8 +21,6 @@
 
 namespace tether {
 
-class BleConnectionManager;
-
 // Operation which sends a keep-alive message to a tether host and receives an
 // update about the host's status.
 class KeepAliveOperation : public MessageTransferOperation {
@@ -32,8 +30,7 @@
     static std::unique_ptr<KeepAliveOperation> NewInstance(
         cryptauth::RemoteDeviceRef device_to_connect,
         device_sync::DeviceSyncClient* device_sync_client,
-        secure_channel::SecureChannelClient* secure_channel_client,
-        BleConnectionManager* connection_manager);
+        secure_channel::SecureChannelClient* secure_channel_client);
 
     static void SetInstanceForTesting(Factory* factory);
 
@@ -41,8 +38,7 @@
     virtual std::unique_ptr<KeepAliveOperation> BuildInstance(
         cryptauth::RemoteDeviceRef device_to_connect,
         device_sync::DeviceSyncClient* device_sync_client,
-        secure_channel::SecureChannelClient* secure_channel_client,
-        BleConnectionManager* connection_manager);
+        secure_channel::SecureChannelClient* secure_channel_client);
 
    private:
     static Factory* factory_instance_;
@@ -63,10 +59,10 @@
   void RemoveObserver(Observer* observer);
 
  protected:
-  KeepAliveOperation(cryptauth::RemoteDeviceRef device_to_connect,
-                     device_sync::DeviceSyncClient* device_sync_client,
-                     secure_channel::SecureChannelClient* secure_channel_client,
-                     BleConnectionManager* connection_manager);
+  KeepAliveOperation(
+      cryptauth::RemoteDeviceRef device_to_connect,
+      device_sync::DeviceSyncClient* device_sync_client,
+      secure_channel::SecureChannelClient* secure_channel_client);
 
   // MessageTransferOperation:
   void OnDeviceAuthenticated(cryptauth::RemoteDeviceRef remote_device) override;
diff --git a/chromeos/components/tether/keep_alive_operation_unittest.cc b/chromeos/components/tether/keep_alive_operation_unittest.cc
index 9132409..178fd722 100644
--- a/chromeos/components/tether/keep_alive_operation_unittest.cc
+++ b/chromeos/components/tether/keep_alive_operation_unittest.cc
@@ -91,9 +91,9 @@
         std::make_unique<secure_channel::FakeSecureChannelClient>();
     fake_ble_connection_manager_ = std::make_unique<FakeBleConnectionManager>();
 
-    operation_ = base::WrapUnique(new KeepAliveOperation(
-        test_device_, fake_device_sync_client_.get(),
-        fake_secure_channel_client_.get(), fake_ble_connection_manager_.get()));
+    operation_ = base::WrapUnique(
+        new KeepAliveOperation(test_device_, fake_device_sync_client_.get(),
+                               fake_secure_channel_client_.get()));
 
     test_observer_ = base::WrapUnique(new TestObserver());
     operation_->AddObserver(test_observer_.get());
diff --git a/chromeos/components/tether/keep_alive_scheduler.cc b/chromeos/components/tether/keep_alive_scheduler.cc
index ef781bf0..644feff8 100644
--- a/chromeos/components/tether/keep_alive_scheduler.cc
+++ b/chromeos/components/tether/keep_alive_scheduler.cc
@@ -20,13 +20,11 @@
     device_sync::DeviceSyncClient* device_sync_client,
     secure_channel::SecureChannelClient* secure_channel_client,
     ActiveHost* active_host,
-    BleConnectionManager* connection_manager,
     HostScanCache* host_scan_cache,
     DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map)
     : KeepAliveScheduler(device_sync_client,
                          secure_channel_client,
                          active_host,
-                         connection_manager,
                          host_scan_cache,
                          device_id_tether_network_guid_map,
                          std::make_unique<base::RepeatingTimer>()) {}
@@ -35,14 +33,12 @@
     device_sync::DeviceSyncClient* device_sync_client,
     secure_channel::SecureChannelClient* secure_channel_client,
     ActiveHost* active_host,
-    BleConnectionManager* connection_manager,
     HostScanCache* host_scan_cache,
     DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map,
     std::unique_ptr<base::RepeatingTimer> timer)
     : device_sync_client_(device_sync_client),
       secure_channel_client_(secure_channel_client),
       active_host_(active_host),
-      connection_manager_(connection_manager),
       host_scan_cache_(host_scan_cache),
       device_id_tether_network_guid_map_(device_id_tether_network_guid_map),
       timer_(std::move(timer)),
@@ -117,8 +113,7 @@
   DCHECK(active_host_device_);
 
   keep_alive_operation_ = KeepAliveOperation::Factory::NewInstance(
-      *active_host_device_, device_sync_client_, secure_channel_client_,
-      connection_manager_);
+      *active_host_device_, device_sync_client_, secure_channel_client_);
   keep_alive_operation_->AddObserver(this);
   keep_alive_operation_->Initialize();
 }
diff --git a/chromeos/components/tether/keep_alive_scheduler.h b/chromeos/components/tether/keep_alive_scheduler.h
index fd36e0e..fe0a695 100644
--- a/chromeos/components/tether/keep_alive_scheduler.h
+++ b/chromeos/components/tether/keep_alive_scheduler.h
@@ -41,7 +41,6 @@
       device_sync::DeviceSyncClient* device_sync_client,
       secure_channel::SecureChannelClient* secure_channel_client,
       ActiveHost* active_host,
-      BleConnectionManager* connection_manager,
       HostScanCache* host_scan_cache,
       DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map);
   virtual ~KeepAliveScheduler();
@@ -62,7 +61,6 @@
       device_sync::DeviceSyncClient* device_sync_client,
       secure_channel::SecureChannelClient* secure_channel_client,
       ActiveHost* active_host,
-      BleConnectionManager* connection_manager,
       HostScanCache* host_scan_cache,
       DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map,
       std::unique_ptr<base::RepeatingTimer> timer);
@@ -74,7 +72,6 @@
   device_sync::DeviceSyncClient* device_sync_client_;
   secure_channel::SecureChannelClient* secure_channel_client_;
   ActiveHost* active_host_;
-  BleConnectionManager* connection_manager_;
   HostScanCache* host_scan_cache_;
   DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map_;
 
diff --git a/chromeos/components/tether/keep_alive_scheduler_unittest.cc b/chromeos/components/tether/keep_alive_scheduler_unittest.cc
index d1a9ea7..30d7d66 100644
--- a/chromeos/components/tether/keep_alive_scheduler_unittest.cc
+++ b/chromeos/components/tether/keep_alive_scheduler_unittest.cc
@@ -13,7 +13,6 @@
 #include "chromeos/chromeos_features.h"
 #include "chromeos/components/tether/device_id_tether_network_guid_map.h"
 #include "chromeos/components/tether/fake_active_host.h"
-#include "chromeos/components/tether/fake_ble_connection_manager.h"
 #include "chromeos/components/tether/fake_host_scan_cache.h"
 #include "chromeos/components/tether/proto_test_util.h"
 #include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h"
@@ -41,12 +40,10 @@
       cryptauth::RemoteDeviceRef device_to_connect,
       device_sync::DeviceSyncClient* device_sync_client,
       secure_channel::SecureChannelClient* secure_channel_client,
-      BleConnectionManager* connection_manager,
       OperationDeletedHandler* handler)
       : KeepAliveOperation(device_to_connect,
                            device_sync_client,
-                           secure_channel_client,
-                           connection_manager),
+                           secure_channel_client),
         handler_(handler),
         remote_device_(device_to_connect) {}
 
@@ -83,12 +80,10 @@
   std::unique_ptr<KeepAliveOperation> BuildInstance(
       cryptauth::RemoteDeviceRef device_to_connect,
       device_sync::DeviceSyncClient* device_sync_client,
-      secure_channel::SecureChannelClient* secure_channel_client,
-      BleConnectionManager* connection_manager) override {
+      secure_channel::SecureChannelClient* secure_channel_client) override {
     num_created_++;
     last_created_ = new FakeKeepAliveOperation(
-        device_to_connect, device_sync_client, secure_channel_client,
-        connection_manager, this);
+        device_to_connect, device_sync_client, secure_channel_client, this);
     return base::WrapUnique(last_created_);
   }
 
@@ -113,7 +108,6 @@
     fake_secure_channel_client_ =
         std::make_unique<secure_channel::FakeSecureChannelClient>();
     fake_active_host_ = std::make_unique<FakeActiveHost>();
-    fake_ble_connection_manager_ = std::make_unique<FakeBleConnectionManager>();
     fake_host_scan_cache_ = std::make_unique<FakeHostScanCache>();
     device_id_tether_network_guid_map_ =
         std::make_unique<DeviceIdTetherNetworkGuidMap>();
@@ -126,8 +120,8 @@
 
     scheduler_ = base::WrapUnique(new KeepAliveScheduler(
         fake_device_sync_client_.get(), fake_secure_channel_client_.get(),
-        fake_active_host_.get(), fake_ble_connection_manager_.get(),
-        fake_host_scan_cache_.get(), device_id_tether_network_guid_map_.get(),
+        fake_active_host_.get(), fake_host_scan_cache_.get(),
+        device_id_tether_network_guid_map_.get(),
         base::WrapUnique(mock_timer_)));
   }
 
@@ -170,7 +164,6 @@
   std::unique_ptr<secure_channel::SecureChannelClient>
       fake_secure_channel_client_;
   std::unique_ptr<FakeActiveHost> fake_active_host_;
-  std::unique_ptr<FakeBleConnectionManager> fake_ble_connection_manager_;
   std::unique_ptr<FakeHostScanCache> fake_host_scan_cache_;
   // TODO(hansberry): Use a fake for this when a real mapping scheme is created.
   std::unique_ptr<DeviceIdTetherNetworkGuidMap>
diff --git a/chromeos/components/tether/message_transfer_operation.cc b/chromeos/components/tether/message_transfer_operation.cc
index b4ebaa4b..038b27183 100644
--- a/chromeos/components/tether/message_transfer_operation.cc
+++ b/chromeos/components/tether/message_transfer_operation.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <set>
 
-#include "chromeos/chromeos_features.h"
 #include "chromeos/components/proximity_auth/logging/logging.h"
 #include "chromeos/components/tether/message_wrapper.h"
 #include "chromeos/components/tether/timer_factory.h"
@@ -95,8 +94,7 @@
     const cryptauth::RemoteDeviceRefList& devices_to_connect,
     secure_channel::ConnectionPriority connection_priority,
     device_sync::DeviceSyncClient* device_sync_client,
-    secure_channel::SecureChannelClient* secure_channel_client,
-    BleConnectionManager* connection_manager)
+    secure_channel::SecureChannelClient* secure_channel_client)
     : remote_devices_(RemoveDuplicatesFromVector(devices_to_connect)),
       device_sync_client_(device_sync_client),
       secure_channel_client_(secure_channel_client),
diff --git a/chromeos/components/tether/message_transfer_operation.h b/chromeos/components/tether/message_transfer_operation.h
index 061e936..c6e1330 100644
--- a/chromeos/components/tether/message_transfer_operation.h
+++ b/chromeos/components/tether/message_transfer_operation.h
@@ -50,11 +50,11 @@
       const cryptauth::RemoteDeviceRefList& devices_to_connect,
       secure_channel::ConnectionPriority connection_priority,
       device_sync::DeviceSyncClient* device_sync_client,
-      secure_channel::SecureChannelClient* secure_channel_client,
-      BleConnectionManager* connection_manager);
+      secure_channel::SecureChannelClient* secure_channel_client);
   virtual ~MessageTransferOperation();
 
-  // Initializes the operation by registering devices with BleConnectionManager.
+  // Initializes the operation by registering device connection listeners with
+  // SecureChannel.
   void Initialize();
 
  protected:
diff --git a/chromeos/components/tether/message_transfer_operation_unittest.cc b/chromeos/components/tether/message_transfer_operation_unittest.cc
index e3105dd..e65e482 100644
--- a/chromeos/components/tether/message_transfer_operation_unittest.cc
+++ b/chromeos/components/tether/message_transfer_operation_unittest.cc
@@ -9,7 +9,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/timer/mock_timer.h"
 #include "chromeos/chromeos_features.h"
-#include "chromeos/components/tether/fake_ble_connection_manager.h"
 #include "chromeos/components/tether/message_wrapper.h"
 #include "chromeos/components/tether/proto_test_util.h"
 #include "chromeos/components/tether/timer_factory.h"
@@ -42,13 +41,11 @@
  public:
   TestOperation(const cryptauth::RemoteDeviceRefList& devices_to_connect,
                 device_sync::DeviceSyncClient* device_sync_client,
-                secure_channel::SecureChannelClient* secure_channel_client,
-                BleConnectionManager* connection_manager)
+                secure_channel::SecureChannelClient* secure_channel_client)
       : MessageTransferOperation(devices_to_connect,
                                  secure_channel::ConnectionPriority::kLow,
                                  device_sync_client,
-                                 secure_channel_client,
-                                 connection_manager) {}
+                                 secure_channel_client) {}
   ~TestOperation() override = default;
 
   bool HasDeviceAuthenticated(cryptauth::RemoteDeviceRef remote_device) {
@@ -194,8 +191,6 @@
     fake_device_sync_client_->set_local_device_metadata(test_local_device_);
     fake_secure_channel_client_ =
         std::make_unique<secure_channel::FakeSecureChannelClient>();
-
-    fake_ble_connection_manager_ = std::make_unique<FakeBleConnectionManager>();
   }
 
   void ConstructOperation(cryptauth::RemoteDeviceRefList remote_devices) {
@@ -216,9 +211,9 @@
           std::move(fake_connection_attempt));
     }
 
-    operation_ = base::WrapUnique(new TestOperation(
-        remote_devices, fake_device_sync_client_.get(),
-        fake_secure_channel_client_.get(), fake_ble_connection_manager_.get()));
+    operation_ = base::WrapUnique(
+        new TestOperation(remote_devices, fake_device_sync_client_.get(),
+                          fake_secure_channel_client_.get()));
     operation_->SetTimerFactoryForTest(base::WrapUnique(test_timer_factory_));
     VerifyOperationStartedAndFinished(false /* has_started */,
                                       false /* has_finished */);
@@ -302,7 +297,6 @@
   std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_;
   std::unique_ptr<secure_channel::FakeSecureChannelClient>
       fake_secure_channel_client_;
-  std::unique_ptr<FakeBleConnectionManager> fake_ble_connection_manager_;
   TestTimerFactory* test_timer_factory_;
   std::unique_ptr<TestOperation> operation_;
 
diff --git a/chromeos/components/tether/mock_host_connection_metrics_logger.cc b/chromeos/components/tether/mock_host_connection_metrics_logger.cc
index 59739854..ddfd0467 100644
--- a/chromeos/components/tether/mock_host_connection_metrics_logger.cc
+++ b/chromeos/components/tether/mock_host_connection_metrics_logger.cc
@@ -5,16 +5,14 @@
 #include "chromeos/components/tether/mock_host_connection_metrics_logger.h"
 
 #include "chromeos/components/tether/active_host.h"
-#include "chromeos/components/tether/ble_connection_manager.h"
 
 namespace chromeos {
 
 namespace tether {
 
 MockHostConnectionMetricsLogger::MockHostConnectionMetricsLogger(
-    BleConnectionManager* connection_manager,
     ActiveHost* active_host)
-    : HostConnectionMetricsLogger(connection_manager, active_host) {}
+    : HostConnectionMetricsLogger(active_host) {}
 
 MockHostConnectionMetricsLogger::~MockHostConnectionMetricsLogger() = default;
 
diff --git a/chromeos/components/tether/mock_host_connection_metrics_logger.h b/chromeos/components/tether/mock_host_connection_metrics_logger.h
index 4b59a47..d5a38bc 100644
--- a/chromeos/components/tether/mock_host_connection_metrics_logger.h
+++ b/chromeos/components/tether/mock_host_connection_metrics_logger.h
@@ -15,12 +15,10 @@
 namespace tether {
 
 class ActiveHost;
-class BleConnectionManager;
 
 class MockHostConnectionMetricsLogger : public HostConnectionMetricsLogger {
  public:
-  MockHostConnectionMetricsLogger(BleConnectionManager* connection_manager,
-                                  ActiveHost* active_host);
+  MockHostConnectionMetricsLogger(ActiveHost* active_host);
   ~MockHostConnectionMetricsLogger() override;
 
   MOCK_METHOD2(RecordConnectionToHostResult,
diff --git a/chromeos/components/tether/synchronous_shutdown_object_container_impl.cc b/chromeos/components/tether/synchronous_shutdown_object_container_impl.cc
index c2671db5..9e33c1c 100644
--- a/chromeos/components/tether/synchronous_shutdown_object_container_impl.cc
+++ b/chromeos/components/tether/synchronous_shutdown_object_container_impl.cc
@@ -144,7 +144,6 @@
           device_sync_client,
           secure_channel_client,
           active_host_.get(),
-          asychronous_container->ble_connection_manager(),
           master_host_scan_cache_.get(),
           device_id_tether_network_guid_map_.get())),
       hotspot_usage_duration_tracker_(
@@ -163,7 +162,6 @@
           network_state_handler_,
           session_manager,
           asychronous_container->tether_host_fetcher(),
-          asychronous_container->ble_connection_manager(),
           host_scan_device_prioritizer_.get(),
           tether_host_response_recorder_.get(),
           gms_core_notifications_state_tracker,
@@ -178,7 +176,6 @@
                                                   session_manager)),
       host_connection_metrics_logger_(
           std::make_unique<HostConnectionMetricsLogger>(
-              asychronous_container->ble_connection_manager(),
               active_host_.get())),
       tether_connector_(std::make_unique<TetherConnectorImpl>(
           device_sync_client,
@@ -187,7 +184,6 @@
           wifi_hotspot_connector_.get(),
           active_host_.get(),
           asychronous_container->tether_host_fetcher(),
-          asychronous_container->ble_connection_manager(),
           tether_host_response_recorder_.get(),
           device_id_tether_network_guid_map_.get(),
           master_host_scan_cache_.get(),
diff --git a/chromeos/components/tether/tether_connector_impl.cc b/chromeos/components/tether/tether_connector_impl.cc
index d2aa349..0e61842 100644
--- a/chromeos/components/tether/tether_connector_impl.cc
+++ b/chromeos/components/tether/tether_connector_impl.cc
@@ -8,7 +8,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "chromeos/components/proximity_auth/logging/logging.h"
 #include "chromeos/components/tether/active_host.h"
-#include "chromeos/components/tether/ble_connection_manager.h"
 #include "chromeos/components/tether/device_id_tether_network_guid_map.h"
 #include "chromeos/components/tether/disconnect_tethering_request_sender.h"
 #include "chromeos/components/tether/host_connection_metrics_logger.h"
@@ -44,7 +43,6 @@
     WifiHotspotConnector* wifi_hotspot_connector,
     ActiveHost* active_host,
     TetherHostFetcher* tether_host_fetcher,
-    BleConnectionManager* connection_manager,
     TetherHostResponseRecorder* tether_host_response_recorder,
     DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map,
     HostScanCache* host_scan_cache,
@@ -58,7 +56,6 @@
       wifi_hotspot_connector_(wifi_hotspot_connector),
       active_host_(active_host),
       tether_host_fetcher_(tether_host_fetcher),
-      connection_manager_(connection_manager),
       tether_host_response_recorder_(tether_host_response_recorder),
       device_id_tether_network_guid_map_(device_id_tether_network_guid_map),
       host_scan_cache_(host_scan_cache),
@@ -262,7 +259,7 @@
   connect_tethering_operation_ =
       ConnectTetheringOperation::Factory::NewInstance(
           *tether_host_to_connect, device_sync_client_, secure_channel_client_,
-          connection_manager_, tether_host_response_recorder_,
+          tether_host_response_recorder_,
           host_scan_cache_->DoesHostRequireSetup(tether_network_guid));
   connect_tethering_operation_->AddObserver(this);
   connect_tethering_operation_->Initialize();
diff --git a/chromeos/components/tether/tether_connector_impl.h b/chromeos/components/tether/tether_connector_impl.h
index f979f3e..6c16c23 100644
--- a/chromeos/components/tether/tether_connector_impl.h
+++ b/chromeos/components/tether/tether_connector_impl.h
@@ -28,7 +28,6 @@
 namespace tether {
 
 class ActiveHost;
-class BleConnectionManager;
 class DeviceIdTetherNetworkGuidMap;
 class DisconnectTetheringRequestSender;
 class HostScanCache;
@@ -53,7 +52,6 @@
       WifiHotspotConnector* wifi_hotspot_connector,
       ActiveHost* active_host,
       TetherHostFetcher* tether_host_fetcher,
-      BleConnectionManager* connection_manager,
       TetherHostResponseRecorder* tether_host_response_recorder,
       DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map,
       HostScanCache* host_scan_cache,
@@ -108,7 +106,6 @@
   WifiHotspotConnector* wifi_hotspot_connector_;
   ActiveHost* active_host_;
   TetherHostFetcher* tether_host_fetcher_;
-  BleConnectionManager* connection_manager_;
   TetherHostResponseRecorder* tether_host_response_recorder_;
   DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map_;
   HostScanCache* host_scan_cache_;
diff --git a/chromeos/components/tether/tether_connector_impl_unittest.cc b/chromeos/components/tether/tether_connector_impl_unittest.cc
index a99b9c8f..23c38c0 100644
--- a/chromeos/components/tether/tether_connector_impl_unittest.cc
+++ b/chromeos/components/tether/tether_connector_impl_unittest.cc
@@ -68,13 +68,11 @@
       cryptauth::RemoteDeviceRef device_to_connect,
       device_sync::DeviceSyncClient* device_sync_client,
       secure_channel::SecureChannelClient* secure_channel_client,
-      BleConnectionManager* connection_manager,
       TetherHostResponseRecorder* tether_host_response_recorder,
       bool setup_required)
       : ConnectTetheringOperation(device_to_connect,
                                   device_sync_client,
                                   secure_channel_client,
-                                  connection_manager,
                                   tether_host_response_recorder,
                                   setup_required),
         setup_required_(setup_required) {}
@@ -122,13 +120,12 @@
       cryptauth::RemoteDeviceRef device_to_connect,
       device_sync::DeviceSyncClient* device_sync_client,
       secure_channel::SecureChannelClient* secure_channel_client,
-      BleConnectionManager* connection_manager,
       TetherHostResponseRecorder* tether_host_response_recorder,
       bool setup_required) override {
     FakeConnectTetheringOperation* operation =
         new FakeConnectTetheringOperation(
             device_to_connect, device_sync_client, secure_channel_client,
-            connection_manager, tether_host_response_recorder, setup_required);
+            tether_host_response_recorder, setup_required);
     created_operations_.push_back(operation);
     return base::WrapUnique(operation);
   }
@@ -177,7 +174,7 @@
         std::make_unique<FakeNotificationPresenter>();
     mock_host_connection_metrics_logger_ =
         base::WrapUnique(new StrictMock<MockHostConnectionMetricsLogger>(
-            fake_ble_connection_manager_.get(), fake_active_host_.get()));
+            fake_active_host_.get()));
     fake_disconnect_tethering_request_sender_ =
         std::make_unique<FakeDisconnectTetheringRequestSender>();
     fake_wifi_hotspot_disconnector_ =
@@ -189,7 +186,6 @@
         fake_device_sync_client_.get(), fake_secure_channel_client_.get(),
         network_state_handler(), fake_wifi_hotspot_connector_.get(),
         fake_active_host_.get(), fake_tether_host_fetcher_.get(),
-        fake_ble_connection_manager_.get(),
         mock_tether_host_response_recorder_.get(),
         device_id_tether_network_guid_map_.get(), fake_host_scan_cache_.get(),
         fake_notification_presenter_.get(),
diff --git a/chromeos/services/ime/public/cpp/rulebased/def/ta_inscript.cc b/chromeos/services/ime/public/cpp/rulebased/def/ta_inscript.cc
index dfcf8eb..329406f9 100644
--- a/chromeos/services/ime/public/cpp/rulebased/def/ta_inscript.cc
+++ b/chromeos/services/ime/public/cpp/rulebased/def/ta_inscript.cc
@@ -63,7 +63,7 @@
     u8"\u0b95",                    // Digit1
     u8"\u0be8",                    // Digit2
     u8"\u0bcd\u0bb0",              // Digit3
-    u8"\u0bb0\u0bcd",              // Digit4
+    u8"\u20b9",                    // Digit4
     u8"\u0b9c\u0bcd\u0b9e",        // Digit5
     u8"\u0ba4\u0bcd\u0bb0",        // Digit6
     u8"\u0b95\u0bcd\u0bb7",        // Digit7
@@ -105,7 +105,7 @@
     u8"\u0bb6",                    // KeyM
     u8"\u0bb7",                    // Comma
     u8"\u0bb8\u0bcd\u0bb0\u0bc0",  // Period
-    u8"",                          // Slash
+    u8"?",                         // Slash
     u8"\u0020",                    // Space
 };
 const char* kAltGr[] = {
@@ -213,7 +213,7 @@
     u8"\u0b95",                    // Digit1
     u8"\u0be8",                    // Digit2
     u8"\u0bcd\u0bb0",              // Digit3
-    u8"\u0bb0\u0bcd",              // Digit4
+    u8"\u20b9",                    // Digit4
     u8"\u0b9c\u0bcd\u0b9e",        // Digit5
     u8"\u0ba4\u0bcd\u0bb0",        // Digit6
     u8"\u0b95\u0bcd\u0bb7",        // Digit7
@@ -255,7 +255,7 @@
     u8"\u0bb6",                    // KeyM
     u8"\u0bb7",                    // Comma
     u8"\u0bb8\u0bcd\u0bb0\u0bc0",  // Period
-    u8"",                          // Slash
+    u8"?",                         // Slash
     u8"\u0020",                    // Space
 };
 const char** kKeyMap[8] = {kNormal,   kShift,        kAltGr,
diff --git a/components/autofill/content/renderer/password_form_conversion_utils.cc b/components/autofill/content/renderer/password_form_conversion_utils.cc
index 2d5646c..ae0bd7e 100644
--- a/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -344,11 +344,24 @@
   return MatchesPattern(str, *kCardCvcReCached);
 }
 
-bool IsEnabledPasswordFieldPresent(const std::vector<FormFieldData>& fields) {
-  return std::find_if(
-             fields.begin(), fields.end(), [](const FormFieldData& field) {
-               return field.is_enabled && field.form_control_type == "password";
-             }) != fields.end();
+// Which types of password fields are present in a form?
+enum class PasswordContents {
+  kEnabled,       // At least one enabled password field.
+  kOnlyDisabled,  // At least one password field, but not enabled.
+  kNone           // No password fields present.
+};
+
+// Returns the PasswordContents reflecting the contents of |fields|.
+PasswordContents GetPasswordContents(const std::vector<FormFieldData>& fields) {
+  PasswordContents result = PasswordContents::kNone;
+  for (const FormFieldData& field : fields) {
+    if (field.form_control_type != "password")
+      continue;
+    result = PasswordContents::kOnlyDisabled;
+    if (field.is_enabled)
+      return PasswordContents::kEnabled;
+  }
+  return result;
 }
 
 // Find the first element in |username_predictions| (i.e. the most reliable
@@ -408,9 +421,21 @@
 
   const FormData& form_data = password_form->form_data;
 
-  // Early exit if no passwords to be typed into.
-  if (!IsEnabledPasswordFieldPresent(form_data.fields))
-    return false;
+  PasswordContents password_contents = GetPasswordContents(form_data.fields);
+  switch (password_contents) {
+    case PasswordContents::kEnabled:
+      // All well, continue parsing.
+      break;
+    case PasswordContents::kOnlyDisabled:
+      // The current parser gives up, but returns a fallback form so that the
+      // newer parser can try parsing as well.
+      password_form->scheme = PasswordForm::SCHEME_HTML;
+      password_form->origin = form_origin;
+      password_form->signon_realm = GetSignOnRealm(password_form->origin);
+      return true;
+    case PasswordContents::kNone:
+      return false;
+  }
 
   // Evaluate the context of the fields.
   if (base::FeatureList::IsEnabled(
diff --git a/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc b/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
index c0626bbc..d2875ae 100644
--- a/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
+++ b/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
@@ -100,12 +100,12 @@
 
   // Appends a disabled text-type field at the end of the form.
   void AddDisabledUsernameField() {
-    html_ += "<INPUT type=\"text\" disabled/>";
+    html_ += "<INPUT name=\"disabled field\" type=\"text\" disabled/>";
   }
 
   // Appends a disabled password-type field at the end of the form.
   void AddDisabledPasswordField() {
-    html_ += "<INPUT type=\"password\" disabled/>";
+    html_ += "<INPUT name=\"disabled field\" type=\"password\" disabled/>";
   }
 
   // Appends a hidden field at the end of the form.
@@ -346,6 +346,10 @@
   EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
 }
 
+// When not enough fields are enabled to parse the form, the result should still
+// be not null. It must contain only minimal information, so that it is not used
+// for fill on load, for example. It must contain the full FormData, so that the
+// new parser can be run as well.
 TEST_F(MAYBE_PasswordFormConversionUtilsTest, OnlyDisabledFields) {
   PasswordFormBuilder builder(kTestFormActionURL);
   builder.AddDisabledUsernameField();
@@ -355,7 +359,11 @@
 
   std::unique_ptr<PasswordForm> password_form =
       LoadHTMLAndConvertForm(html, nullptr, false);
-  ASSERT_FALSE(password_form);
+  ASSERT_TRUE(password_form);
+  EXPECT_TRUE(password_form->username_element.empty());
+  EXPECT_TRUE(password_form->password_element.empty());
+  EXPECT_TRUE(password_form->new_password_element.empty());
+  EXPECT_EQ(2u, password_form->form_data.fields.size());
 }
 
 TEST_F(MAYBE_PasswordFormConversionUtilsTest,
diff --git a/components/autofill/core/common/autofill_constants.cc b/components/autofill/core/common/autofill_constants.cc
index 53a8b46..0a9a163 100644
--- a/components/autofill/core/common/autofill_constants.cc
+++ b/components/autofill/core/common/autofill_constants.cc
@@ -18,6 +18,8 @@
 
 const char kSettingsOrigin[] = "Chrome settings";
 
+const char kPrivacySettingsURL[] = "chrome://settings/privacy";
+
 size_t MinRequiredFieldsForHeuristics() {
   return base::FeatureList::IsEnabled(
              autofill::features::kAutofillEnforceMinRequiredFieldsForHeuristics)
diff --git a/components/autofill/core/common/autofill_constants.h b/components/autofill/core/common/autofill_constants.h
index 2ab64b6..8ee89a76 100644
--- a/components/autofill/core/common/autofill_constants.h
+++ b/components/autofill/core/common/autofill_constants.h
@@ -17,6 +17,9 @@
 // The origin of an AutofillDataModel created or modified in the settings page.
 extern const char kSettingsOrigin[];
 
+// The privacy page URL of the chrome settings.
+extern const char kPrivacySettingsURL[];
+
 // The number of fields required by Autofill to execute its heuristic and
 // crowd-sourcing query/upload routines.
 size_t MinRequiredFieldsForHeuristics();
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index a4a1045..d7004b7 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -118,6 +118,11 @@
 const base::Feature kAutofillGetPaymentsIdentityFromSync{
     "AutofillGetPaymentsIdentityFromSync", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// When enabled, autofill suggestions are displayed in the keyboard accessory
+// instead of the regular popup.
+const base::Feature kAutofillKeyboardAccessory{
+    "AutofillKeyboardAccessory", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // When enabled, the local card migration dialog will show the progress
 // and result of the migration after starting the migration. When disabled,
 // there is no feedback for the migration.
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 7522d3b..31cf76ff 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -41,6 +41,7 @@
 extern const base::Feature kAutofillEnforceMinRequiredFieldsForUpload;
 extern const base::Feature kAutofillExpandedPopupViews;
 extern const base::Feature kAutofillGetPaymentsIdentityFromSync;
+extern const base::Feature kAutofillKeyboardAccessory;
 extern const base::Feature kAutofillLocalCardMigrationShowFeedback;
 extern const base::Feature kAutofillManualFallback;
 extern const base::Feature kAutofillManualFallbackPhaseTwo;
diff --git a/components/autofill/core/common/autofill_util.cc b/components/autofill/core/common/autofill_util.cc
index 44917ea..0191e66 100644
--- a/components/autofill/core/common/autofill_util.cc
+++ b/components/autofill/core/common/autofill_util.cc
@@ -17,12 +17,13 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/autofill_switches.h"
 
 namespace autofill {
 
-const base::Feature kAutofillKeyboardAccessory{
-    "AutofillKeyboardAccessory", base::FEATURE_DISABLED_BY_DEFAULT};
+using features::kAutofillKeyboardAccessory;
+
 const char kAutofillKeyboardAccessoryAnimationDurationKey[] =
     "animation_duration_millis";
 const char kAutofillKeyboardAccessoryLimitLabelWidthKey[] =
diff --git a/components/autofill/core/common/autofill_util.h b/components/autofill/core/common/autofill_util.h
index 3f8f74f..437fdb4 100644
--- a/components/autofill/core/common/autofill_util.h
+++ b/components/autofill/core/common/autofill_util.h
@@ -19,7 +19,6 @@
 
 namespace autofill {
 
-extern const base::Feature kAutofillKeyboardAccessory;
 extern const char kAutofillKeyboardAccessoryAnimationDurationKey[];
 extern const char kAutofillKeyboardAccessoryLimitLabelWidthKey[];
 extern const char kAutofillKeyboardAccessoryHintKey[];
diff --git a/components/autofill_assistant_strings.grdp b/components/autofill_assistant_strings.grdp
index 2bb6a97..d3c3be5 100644
--- a/components/autofill_assistant_strings.grdp
+++ b/components/autofill_assistant_strings.grdp
@@ -17,7 +17,10 @@
       Confirm
     </message>
     <message name="IDS_AUTOFILL_ASSISTANT_TERMS" desc="The text for the terms and service acceptance checkbox. Sentence-cased." formatter_data="android_java">
-      I know the terms and conditions, privacy policy and right of withdrawal of <ph name="BEGIN_BOLD">&lt;b&gt;</ph><ph name="ORIGIN">%1$s<ex>google.com</ex></ph><ph name="END_BOLD">&lt;/b&gt;</ph> (leave unchecked to read).
+      I know the terms &amp; conditions, privacy policy and right of withdrawal of <ph name="BEGIN_BOLD">&lt;b&gt;</ph><ph name="ORIGIN">%1$s<ex>google.com</ex></ph><ph name="END_BOLD">&lt;/b&gt;</ph> (leave unchecked to read).
+    </message>
+    <message name="IDS_AUTOFILL_ASSISTANT_TERMS_TITLE" desc="The title for the terms and service checkbox." formatter_data="android_java">
+      Terms &amp; Conditions
     </message>
     <message name="IDS_AUTOFILL_ASSISTANT_DETAILS_DIFFER" desc="Shown as Status Message when details differ." formatter_data="android_java">
       The movie screening is different, do you want to continue?
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc
index 4efa913..56d2c7b 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -48,7 +48,6 @@
 #include "components/sync_bookmarks/bookmark_data_type_controller.h"
 #include "components/sync_bookmarks/bookmark_model_associator.h"
 #include "components/sync_bookmarks/bookmark_sync_service.h"
-#include "components/sync_sessions/session_data_type_controller.h"
 #include "components/sync_sessions/session_model_type_controller.h"
 #include "components/sync_sessions/session_sync_service.h"
 
@@ -57,7 +56,6 @@
 using sync_bookmarks::BookmarkChangeProcessor;
 using sync_bookmarks::BookmarkDataTypeController;
 using sync_bookmarks::BookmarkModelAssociator;
-using sync_sessions::SessionDataTypeController;
 using syncer::AsyncDirectoryTypeController;
 using syncer::DataTypeController;
 using syncer::DataTypeManager;
@@ -138,8 +136,7 @@
 
 syncer::DataTypeController::TypeVector
 ProfileSyncComponentsFactoryImpl::CreateCommonDataTypeControllers(
-    syncer::ModelTypeSet disabled_types,
-    syncer::LocalDeviceInfoProvider* local_device_info_provider) {
+    syncer::ModelTypeSet disabled_types) {
   syncer::DataTypeController::TypeVector controllers;
   const base::RepeatingClosure dump_stack =
       base::BindRepeating(&syncer::ReportUnrecoverableError, channel_);
@@ -273,7 +270,6 @@
           base::BindRepeating(
               &sync_sessions::SessionSyncService::ProxyTabsStateChanged,
               base::Unretained(sync_client_->GetSessionSyncService()))));
-      if (FeatureList::IsEnabled(switches::kSyncUSSSessions)) {
         controllers.push_back(
             std::make_unique<sync_sessions::SessionModelTypeController>(
                 sync_client_->GetPrefService(),
@@ -282,11 +278,6 @@
                         ->GetControllerDelegate()
                         .get()),
                 history_disabled_pref_));
-      } else {
-        controllers.push_back(std::make_unique<SessionDataTypeController>(
-            dump_stack, sync_client_, local_device_info_provider,
-            history_disabled_pref_));
-      }
     }
 
     // Favicon sync is enabled by default. Register unless explicitly disabled.
diff --git a/components/browser_sync/profile_sync_components_factory_impl.h b/components/browser_sync/profile_sync_components_factory_impl.h
index 249395f..d050946 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.h
+++ b/components/browser_sync/profile_sync_components_factory_impl.h
@@ -57,8 +57,7 @@
 
   // SyncApiComponentFactory implementation:
   syncer::DataTypeController::TypeVector CreateCommonDataTypeControllers(
-      syncer::ModelTypeSet disabled_types,
-      syncer::LocalDeviceInfoProvider* local_device_info_provider) override;
+      syncer::ModelTypeSet disabled_types) override;
   std::unique_ptr<syncer::DataTypeManager> CreateDataTypeManager(
       syncer::ModelTypeSet initial_types,
       const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index 412c2fb2..2fcaab045 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -173,8 +173,6 @@
       sync_service_url_(
           syncer::GetSyncServiceURL(*base::CommandLine::ForCurrentProcess(),
                                     init_params.channel)),
-      user_events_separate_pref_group_(
-          init_params.user_events_separate_pref_group),
       crypto_(
           base::BindRepeating(&ProfileSyncService::NotifyObservers,
                               base::Unretained(this)),
@@ -260,8 +258,8 @@
           /*dump_stack=*/base::BindRepeating(&syncer::ReportUnrecoverableError,
                                              channel_)));
 
-  data_type_controllers_ = BuildDataTypeControllerMap(
-      sync_client_->CreateDataTypeControllers(local_device_.get()));
+  data_type_controllers_ =
+      BuildDataTypeControllerMap(sync_client_->CreateDataTypeControllers());
 
   if (gaia_cookie_manager_service_)
     gaia_cookie_manager_service_->AddObserver(this);
@@ -1058,10 +1056,6 @@
     return;
 
   current_experiments_ = experiments;
-
-  sync_client_->GetPrefService()->SetBoolean(
-      invalidation::prefs::kInvalidationServiceUseGCMChannel,
-      experiments.gcm_invalidations_enabled);
 }
 
 void ProfileSyncService::OnConnectionStatusChange(
@@ -1377,8 +1371,7 @@
 
   const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
   // Will only enable those types that are registered and preferred.
-  sync_prefs_.SetPreferredDataTypes(registered_types, chosen_types,
-                                    user_events_separate_pref_group_);
+  sync_prefs_.SetPreferredDataTypes(registered_types, chosen_types);
 
   // Now reconfigure the DTM.
   ReconfigureDatatypeManager(/*bypass_setup_in_progress_check=*/false);
@@ -1415,8 +1408,7 @@
 syncer::ModelTypeSet ProfileSyncService::GetPreferredDataTypes() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   syncer::ModelTypeSet preferred_types =
-      Union(sync_prefs_.GetPreferredDataTypes(GetRegisteredDataTypes(),
-                                              user_events_separate_pref_group_),
+      Union(sync_prefs_.GetPreferredDataTypes(GetRegisteredDataTypes()),
             syncer::ControlTypes());
   if (IsLocalSyncEnabled()) {
     preferred_types.Remove(syncer::APP_LIST);
@@ -1431,7 +1423,7 @@
   syncer::ModelTypeSet forced_types;
   for (const syncer::SyncTypePreferenceProvider* provider :
        preference_providers_) {
-    forced_types.PutAll(provider->GetPreferredDataTypes());
+    forced_types.PutAll(provider->GetForcedDataTypes());
   }
   return Intersection(forced_types, GetRegisteredDataTypes());
 }
diff --git a/components/browser_sync/profile_sync_service.h b/components/browser_sync/profile_sync_service.h
index 0a94164..2bd731d 100644
--- a/components/browser_sync/profile_sync_service.h
+++ b/components/browser_sync/profile_sync_service.h
@@ -208,7 +208,6 @@
     network::NetworkConnectionTracker* network_connection_tracker = nullptr;
     std::string debug_identifier;
     version_info::Channel channel = version_info::Channel::UNKNOWN;
-    bool user_events_separate_pref_group = false;
 
    private:
     DISALLOW_COPY_AND_ASSIGN(InitParams);
@@ -598,10 +597,6 @@
   // This specifies where to find the sync server.
   const GURL sync_service_url_;
 
-  // Whether USER_EVENTS model type has a separate pref group instead of
-  // being bundled with the TYPED_URLS model type.
-  const bool user_events_separate_pref_group_;
-
   // A utility object containing logic and state relating to encryption.
   syncer::SyncServiceCrypto crypto_;
 
diff --git a/components/browser_sync/profile_sync_service_autofill_unittest.cc b/components/browser_sync/profile_sync_service_autofill_unittest.cc
index a5823ca..1efb4ab 100644
--- a/components/browser_sync/profile_sync_service_autofill_unittest.cc
+++ b/components/browser_sync/profile_sync_service_autofill_unittest.cc
@@ -434,7 +434,7 @@
     CreateSyncService(std::move(sync_client_owned_), std::move(callback));
 
     EXPECT_CALL(*profile_sync_service_bundle()->component_factory(),
-                CreateCommonDataTypeControllers(_, _))
+                CreateCommonDataTypeControllers(_))
         .WillOnce(testing::InvokeWithoutArgs([=]() {
           syncer::DataTypeController::TypeVector controllers;
           controllers.push_back(
diff --git a/components/browser_sync/profile_sync_service_startup_unittest.cc b/components/browser_sync/profile_sync_service_startup_unittest.cc
index bd021ddd4..97d20d7 100644
--- a/components/browser_sync/profile_sync_service_startup_unittest.cc
+++ b/components/browser_sync/profile_sync_service_startup_unittest.cc
@@ -82,7 +82,7 @@
         profile_sync_service_bundle_.CreateBasicInitParams(start_behavior,
                                                            builder.Build());
 
-    ON_CALL(*component_factory(), CreateCommonDataTypeControllers(_, _))
+    ON_CALL(*component_factory(), CreateCommonDataTypeControllers(_))
         .WillByDefault(InvokeWithoutArgs([=]() {
           syncer::DataTypeController::TypeVector controllers;
           for (syncer::ModelType type : registered_types) {
diff --git a/components/browser_sync/profile_sync_service_unittest.cc b/components/browser_sync/profile_sync_service_unittest.cc
index 7a586418..ec1078ee 100644
--- a/components/browser_sync/profile_sync_service_unittest.cc
+++ b/components/browser_sync/profile_sync_service_unittest.cc
@@ -193,7 +193,7 @@
                                                            builder.Build());
     service_ = std::make_unique<ProfileSyncService>(std::move(init_params));
 
-    ON_CALL(*component_factory(), CreateCommonDataTypeControllers(_, _))
+    ON_CALL(*component_factory(), CreateCommonDataTypeControllers(_))
         .WillByDefault(testing::InvokeWithoutArgs([=]() {
           syncer::DataTypeController::TypeVector controllers;
           controllers.push_back(
@@ -223,7 +223,7 @@
 
     service_ = std::make_unique<ProfileSyncService>(std::move(init_params));
 
-    ON_CALL(*component_factory(), CreateCommonDataTypeControllers(_, _))
+    ON_CALL(*component_factory(), CreateCommonDataTypeControllers(_))
         .WillByDefault(testing::InvokeWithoutArgs([=]() {
           syncer::DataTypeController::TypeVector controllers;
           controllers.push_back(
diff --git a/components/browser_sync/sync_user_settings_impl.cc b/components/browser_sync/sync_user_settings_impl.cc
index aeee8b7..cd2fdd40 100644
--- a/components/browser_sync/sync_user_settings_impl.cc
+++ b/components/browser_sync/sync_user_settings_impl.cc
@@ -68,7 +68,7 @@
 void SyncUserSettingsImpl::SetChosenDataTypes(bool sync_everything,
                                               syncer::ModelTypeSet types) {
   // TODO(crbug.com/884159): Write to prefs directly (might be tricky because it
-  // needs the registered types and the user_events_separate_pref_group flag).
+  // needs the registered types).
   service_->OnUserChoseDatatypes(sync_everything, types);
 }
 
diff --git a/components/invalidation/impl/invalidation_prefs.cc b/components/invalidation/impl/invalidation_prefs.cc
index ea9c7931..80278f5 100644
--- a/components/invalidation/impl/invalidation_prefs.cc
+++ b/components/invalidation/impl/invalidation_prefs.cc
@@ -18,11 +18,6 @@
 // yet.  Used to keep invalidation clients in sync in case of a restart.
 const char kInvalidatorSavedInvalidations[] = "invalidator.saved_invalidations";
 
-// Boolean indicating that TiclInvalidationService should use GCM channel.
-// False or lack of settings means XMPPPushClient channel.
-const char kInvalidationServiceUseGCMChannel[] =
-    "invalidation_service.use_gcm_channel";
-
 // The prefference for storing client ID for the invalidator.
 const char kFCMInvalidationClientIDCache[] = "fcm.invalidation.client_id_cache";
 
diff --git a/components/invalidation/impl/invalidation_prefs.h b/components/invalidation/impl/invalidation_prefs.h
index 35b028b..ec6492d 100644
--- a/components/invalidation/impl/invalidation_prefs.h
+++ b/components/invalidation/impl/invalidation_prefs.h
@@ -14,8 +14,6 @@
 
 extern const char kInvalidatorSavedInvalidations[];
 
-extern const char kInvalidationServiceUseGCMChannel[];
-
 extern const char kFCMInvalidationClientIDCache[];
 
 }  // namespace prefs
diff --git a/components/invalidation/impl/invalidation_switches.cc b/components/invalidation/impl/invalidation_switches.cc
index 8411af3e..63ed820 100644
--- a/components/invalidation/impl/invalidation_switches.cc
+++ b/components/invalidation/impl/invalidation_switches.cc
@@ -7,9 +7,10 @@
 namespace invalidation {
 namespace switches {
 
-// Invalidation service should use GCM network channel even if experiment is not
-// enabled.
+#if defined(OS_CHROMEOS)
+// Device invalidation service should use GCM network channel.
 const char kInvalidationUseGCMChannel[] = "invalidation-use-gcm-channel";
+#endif  // OS_CHROMEOS
 
 // Overrides the default host:port used for notifications.
 const char kSyncNotificationHostPort[] = "sync-notification-host-port";
diff --git a/components/invalidation/impl/invalidation_switches.h b/components/invalidation/impl/invalidation_switches.h
index 2dd3145c..2f816fb 100644
--- a/components/invalidation/impl/invalidation_switches.h
+++ b/components/invalidation/impl/invalidation_switches.h
@@ -6,11 +6,15 @@
 #define COMPONENTS_INVALIDATION_IMPL_INVALIDATION_SWITCHES_H
 
 #include "base/feature_list.h"
+#include "build/build_config.h"
 
 namespace invalidation {
 namespace switches {
 
+#if defined(OS_CHROMEOS)
 extern const char kInvalidationUseGCMChannel[];
+#endif  // OS_CHROMEOS
+
 extern const char kSyncNotificationHostPort[];
 extern const char kSyncAllowInsecureXmppConnection[];
 extern const base::Feature kFCMInvalidations;
diff --git a/components/invalidation/impl/profile_invalidation_provider.cc b/components/invalidation/impl/profile_invalidation_provider.cc
index 1d6a294..ba1ec9c 100644
--- a/components/invalidation/impl/profile_invalidation_provider.cc
+++ b/components/invalidation/impl/profile_invalidation_provider.cc
@@ -36,10 +36,6 @@
 // static
 void ProfileInvalidationProvider::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
-  registry->RegisterBooleanPref(
-      prefs::kInvalidationServiceUseGCMChannel,
-      true);  // if no value in prefs, use GCM channel.
-
   registry->RegisterStringPref(prefs::kFCMInvalidationClientIDCache,
                                /*default_value=*/std::string());
 }
diff --git a/components/invalidation/impl/ticl_profile_settings_provider.cc b/components/invalidation/impl/ticl_profile_settings_provider.cc
index e9424f2..af4364f 100644
--- a/components/invalidation/impl/ticl_profile_settings_provider.cc
+++ b/components/invalidation/impl/ticl_profile_settings_provider.cc
@@ -19,10 +19,6 @@
     : prefs_(prefs) {
   registrar_.Init(prefs_);
   registrar_.Add(
-      prefs::kInvalidationServiceUseGCMChannel,
-      base::Bind(&TiclProfileSettingsProvider::FireOnUseGCMChannelChanged,
-                 base::Unretained(this)));
-  registrar_.Add(
       gcm::prefs::kGCMChannelStatus,
       base::Bind(&TiclProfileSettingsProvider::FireOnUseGCMChannelChanged,
                  base::Unretained(this)));
@@ -31,19 +27,7 @@
 TiclProfileSettingsProvider::~TiclProfileSettingsProvider() {}
 
 bool TiclProfileSettingsProvider::UseGCMChannel() const {
-  if (prefs_->GetBoolean(prefs::kInvalidationServiceUseGCMChannel)) {
-    // Use GCM channel if it was enabled via prefs.
-    return true;
-  }
-
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kInvalidationUseGCMChannel)) {
-    // Use GCM channel if it was enabled via a command-line switch.
-    return true;
-  }
-
-  // By default, do not use GCM channel.
-  return false;
+  return true;
 }
 
 }  // namespace invalidation
diff --git a/components/invalidation/impl/ticl_profile_settings_provider_unittest.cc b/components/invalidation/impl/ticl_profile_settings_provider_unittest.cc
index 88ecb69..4227742 100644
--- a/components/invalidation/impl/ticl_profile_settings_provider_unittest.cc
+++ b/components/invalidation/impl/ticl_profile_settings_provider_unittest.cc
@@ -90,30 +90,17 @@
   // Default value should be GCM channel.
   EXPECT_EQ(TiclInvalidationService::GCM_NETWORK_CHANNEL, GetNetworkChannel());
 
-  // If GCM is enabled and invalidation channel setting is not set or set to
-  // true then use GCM channel.
+  // If GCM is enabled then use GCM channel.
   pref_service_.SetBoolean(gcm::prefs::kGCMChannelStatus, true);
-  pref_service_.SetBoolean(prefs::kInvalidationServiceUseGCMChannel, true);
-  EXPECT_EQ(TiclInvalidationService::GCM_NETWORK_CHANNEL, GetNetworkChannel());
-
-  pref_service_.SetBoolean(gcm::prefs::kGCMChannelStatus, true);
-  pref_service_.ClearPref(prefs::kInvalidationServiceUseGCMChannel);
   EXPECT_EQ(TiclInvalidationService::GCM_NETWORK_CHANNEL, GetNetworkChannel());
 
   pref_service_.ClearPref(gcm::prefs::kGCMChannelStatus);
-  pref_service_.SetBoolean(prefs::kInvalidationServiceUseGCMChannel, true);
   EXPECT_EQ(TiclInvalidationService::GCM_NETWORK_CHANNEL, GetNetworkChannel());
 
   // If invalidation channel setting says use GCM but GCM is not enabled, do not
   // fall back to push channel.
   pref_service_.SetBoolean(gcm::prefs::kGCMChannelStatus, false);
-  pref_service_.SetBoolean(prefs::kInvalidationServiceUseGCMChannel, true);
   EXPECT_EQ(TiclInvalidationService::GCM_NETWORK_CHANNEL, GetNetworkChannel());
-
-  // If invalidation channel setting is set to false, fall back to push channel.
-  pref_service_.SetBoolean(gcm::prefs::kGCMChannelStatus, true);
-  pref_service_.SetBoolean(prefs::kInvalidationServiceUseGCMChannel, false);
-  EXPECT_EQ(TiclInvalidationService::PUSH_CLIENT_CHANNEL, GetNetworkChannel());
 }
 
 }  // namespace invalidation
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index 9c55d036..cf11964 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -474,8 +474,7 @@
     const GURL& url,
     const AutocompleteInput& input,
     const TemplateURLService* template_url_service,
-    const base::string16& keyword,
-    const std::string& additional_query_params) {
+    const base::string16& keyword) {
   if (!url.is_valid())
     return url;
 
@@ -496,12 +495,10 @@
         stripped_destination_url,
         template_url_service->search_terms_data(),
         &search_terms)) {
-      TemplateURLRef::SearchTermsArgs search_terms_args(search_terms);
-      if (!additional_query_params.empty())
-        search_terms_args.additional_query_params = additional_query_params;
       stripped_destination_url =
           GURL(template_url->url_ref().ReplaceSearchTerms(
-              search_terms_args, template_url_service->search_terms_data()));
+              TemplateURLRef::SearchTermsArgs(search_terms),
+              template_url_service->search_terms_data()));
     }
   }
 
@@ -624,9 +621,8 @@
 void AutocompleteMatch::ComputeStrippedDestinationURL(
     const AutocompleteInput& input,
     TemplateURLService* template_url_service) {
-  stripped_destination_url = GURLToStrippedGURL(
-      destination_url, input, template_url_service, keyword,
-      search_terms_args ? search_terms_args->additional_query_params : "");
+  stripped_destination_url =
+      GURLToStrippedGURL(destination_url, input, template_url_service, keyword);
 }
 
 void AutocompleteMatch::GetKeywordUIState(
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h
index 720a4c0..7f98a7ef 100644
--- a/components/omnibox/browser/autocomplete_match.h
+++ b/components/omnibox/browser/autocomplete_match.h
@@ -233,16 +233,10 @@
   // - If the match's keyword is known, it can be provided in |keyword|.
   //   Otherwise, it can be left empty and the template URL (if any) is
   //   determined from the destination's hostname.
-  // - If |additional_query_params| is provided, these will be added to the
-  //   resulting URL in the cases where a template URL is used. This is used to
-  //   distinguish cases such as entity suggestions where the response contains
-  //   additional meaningful parameters beyond the search terms themselves.
-  static GURL GURLToStrippedGURL(
-      const GURL& url,
-      const AutocompleteInput& input,
-      const TemplateURLService* template_url_service,
-      const base::string16& keyword,
-      const std::string& additional_query_params = "");
+  static GURL GURLToStrippedGURL(const GURL& url,
+                                 const AutocompleteInput& input,
+                                 const TemplateURLService* template_url_service,
+                                 const base::string16& keyword);
 
   // Sets the |match_in_scheme|, |match_in_subdomain|, and |match_after_host|
   // flags based on the provided |url| and list of substring |match_positions|.
diff --git a/components/password_manager/core/browser/new_password_form_manager.cc b/components/password_manager/core/browser/new_password_form_manager.cc
index e791d75..49afff9 100644
--- a/components/password_manager/core/browser/new_password_form_manager.cc
+++ b/components/password_manager/core/browser/new_password_form_manager.cc
@@ -284,6 +284,30 @@
 }
 
 void NewPasswordFormManager::Update(const PasswordForm& credentials_to_update) {
+  metrics_util::LogPasswordAcceptedSaveUpdateSubmissionIndicatorEvent(
+      parsed_submitted_form_->submission_event);
+  metrics_recorder_->SetSubmissionIndicatorEvent(
+      parsed_submitted_form_->submission_event);
+
+  std::unique_ptr<PasswordForm> parsed_observed_form =
+      parser_.Parse(observed_form_, FormDataParser::Mode::kFilling);
+  FormStructure form_structure(credentials_to_update.form_data);
+  votes_uploader_.UploadPasswordVote(
+      *parsed_observed_form, *parsed_submitted_form_, autofill::NEW_PASSWORD,
+      form_structure.FormSignatureAsStr());
+
+  base::string16 password_to_save = pending_credentials_.password_value;
+  bool skip_zero_click = pending_credentials_.skip_zero_click;
+  pending_credentials_ = credentials_to_update;
+  pending_credentials_.password_value = password_to_save;
+  pending_credentials_.skip_zero_click = skip_zero_click;
+  pending_credentials_.preferred = true;
+  is_new_login_ = false;
+  ProcessUpdate();
+  std::vector<PasswordForm> more_credentials_to_update =
+      FindOtherCredentialsToUpdate();
+  form_saver_->Update(pending_credentials_, best_matches_,
+                      &more_credentials_to_update, nullptr);
 }
 
 void NewPasswordFormManager::UpdateUsername(
diff --git a/components/password_manager/core/browser/new_password_form_manager_unittest.cc b/components/password_manager/core/browser/new_password_form_manager_unittest.cc
index 20436081..d767bf94 100644
--- a/components/password_manager/core/browser/new_password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/new_password_form_manager_unittest.cc
@@ -1339,6 +1339,43 @@
                                       expected_differences_mask, 1);
 }
 
+TEST_F(NewPasswordFormManagerTest, Update) {
+  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
+
+  PasswordForm not_best_saved_match = saved_match_;
+  not_best_saved_match.preferred = false;
+  PasswordForm saved_match_another_username = saved_match_;
+  saved_match_another_username.username_value += ASCIIToUTF16("1");
+  fetcher_->SetNonFederated({&saved_match_, &saved_match_another_username}, 0u);
+
+  FormData submitted_form = observed_form_;
+  base::string16 username = saved_match_.username_value;
+  base::string16 new_password = saved_match_.password_value + ASCIIToUTF16("1");
+  submitted_form.fields[kUsernameFieldIndex].value = username;
+  submitted_form.fields[kPasswordFieldIndex].value = new_password;
+
+  EXPECT_TRUE(
+      form_manager_->SetSubmittedFormIfIsManaged(submitted_form, &driver_));
+
+  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
+  PasswordForm updated_form;
+  std::map<base::string16, const PasswordForm*> best_matches;
+  std::vector<PasswordForm> credentials_to_update;
+  EXPECT_CALL(form_saver, Update(_, _, _, nullptr))
+      .WillOnce(DoAll(SaveArg<0>(&updated_form), SaveArg<1>(&best_matches),
+                      SaveArgPointee<2>(&credentials_to_update)));
+
+  form_manager_->Update(saved_match_);
+
+  EXPECT_TRUE(ArePasswordFormUniqueKeyEqual(saved_match_, updated_form));
+  EXPECT_TRUE(updated_form.preferred);
+  EXPECT_EQ(new_password, updated_form.password_value);
+  EXPECT_EQ(2u, best_matches.size());
+  ASSERT_TRUE(best_matches.find(username) != best_matches.end());
+  EXPECT_EQ(saved_match_, *best_matches[username]);
+  EXPECT_TRUE(credentials_to_update.empty());
+}
+
 }  // namespace
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_form_filling.cc b/components/password_manager/core/browser/password_form_filling.cc
index cfc7edc0..5beaa823 100644
--- a/components/password_manager/core/browser/password_form_filling.cc
+++ b/components/password_manager/core/browser/password_form_filling.cc
@@ -167,11 +167,16 @@
       base::FeatureList::IsEnabled(features::kNewPasswordFormParsing)) {
     PasswordFormMetricsRecorder::FillOnLoad fill_on_load_result =
         PasswordFormMetricsRecorder::FillOnLoad::kSame;
-    if (did_fill_on_load != will_fill_on_load) {
+    // Note: The fill on load never happens if |will_fill_on_load| is false,
+    // because PasswordAutofillAgent won't be able to locate the "current
+    // password" field to fill. So even if |did_fill_on_load| is true and
+    // |will_fill_on_load| is false, the behaviour of Chrome does not change if
+    // either of them is picked for |form_good_for_filling|. So the only
+    // interesting case to report is when |did...| is false and |will...| is
+    // true.
+    if (!did_fill_on_load && will_fill_on_load) {
       fill_on_load_result =
-          will_fill_on_load
-              ? PasswordFormMetricsRecorder::FillOnLoad::kStartsFillingOnLoad
-              : PasswordFormMetricsRecorder::FillOnLoad::kStopsFillingOnLoad;
+          PasswordFormMetricsRecorder::FillOnLoad::kStartsFillingOnLoad;
     }
     metrics_recorder->RecordFillOnLoad(fill_on_load_result);
   }
diff --git a/components/password_manager/core/browser/password_form_filling_unittest.cc b/components/password_manager/core/browser/password_form_filling_unittest.cc
index df3acdd..f27f7cc 100644
--- a/components/password_manager/core/browser/password_form_filling_unittest.cc
+++ b/components/password_manager/core/browser/password_form_filling_unittest.cc
@@ -152,29 +152,35 @@
 TEST_F(PasswordFormFillingTest, TestFillOnLoadReported) {
   const struct {
     const char* description;
-    bool new_password_present;
+    bool new_password_name_empty;
     bool current_password_present;
     PasswordFormMetricsRecorder::FillOnLoad expected_comparison;
   } kTestCases[] = {
       {
           .description = "Fills on load",
-          .new_password_present = false,
+          .new_password_name_empty = true,
           .current_password_present = true,
           .expected_comparison = PasswordFormMetricsRecorder::FillOnLoad::kSame,
       },
       {
           .description = "Does not fill on load",
-          .new_password_present = true,
+          .new_password_name_empty = false,
           .current_password_present = false,
           .expected_comparison = PasswordFormMetricsRecorder::FillOnLoad::kSame,
       },
       {
           .description = "Did not fill on load, will fill on load",
-          .new_password_present = true,
+          .new_password_name_empty = false,
           .current_password_present = true,
           .expected_comparison =
               PasswordFormMetricsRecorder::FillOnLoad::kStartsFillingOnLoad,
       },
+      {
+          .description = "New password field present but its name is empty",
+          .new_password_name_empty = true,
+          .current_password_present = false,
+          .expected_comparison = PasswordFormMetricsRecorder::FillOnLoad::kSame,
+      },
   };
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(features::kNewPasswordFormParsing);
@@ -192,7 +198,7 @@
     best_matches[saved_match_.username_value] = &saved_match_;
 
     PasswordForm observed_form = observed_form_;
-    if (test_case.new_password_present)
+    if (!test_case.new_password_name_empty)
       observed_form.new_password_element = ASCIIToUTF16("New Passwd");
     if (!test_case.current_password_present)
       observed_form.password_element.clear();
diff --git a/components/password_manager/core/browser/password_form_metrics_recorder.h b/components/password_manager/core/browser/password_form_metrics_recorder.h
index 1baf4a85..15a625b3 100644
--- a/components/password_manager/core/browser/password_form_metrics_recorder.h
+++ b/components/password_manager/core/browser/password_form_metrics_recorder.h
@@ -190,15 +190,16 @@
   // the UKM PasswordForm.FillOnLoad to report which changes in behaviour this
   // causes.
   enum class FillOnLoad {
-    // The old and the new condition evaluate to the same result.
+    // No change in fill-on-load behaviour, either because the old and the new
+    // condition evaluate to the same result, or because the new condition being
+    // false breaks fill-on-load even in the case when only the old condition is
+    // checked.
     kSame,
     // The old condition prevented fill on load, the new allows it. This happens
     // for forms with both 'current-password' and 'new-password' fields.
     kStartsFillingOnLoad,
-    // The old condition allowed filling on load, the new prevents it. This
-    // corresponds to forms with neither 'current-password' nor 'new-password'
-    // fields, so it should never happen. It is included for completeness.
-    kStopsFillingOnLoad
+    // Obsolete, cannot happen.
+    kObsoleteStopsFillingOnLoad
   };
 
   // Indicator whether the user has seen a password generation popup and why.
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 6e73f78..246cbb1 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -2271,11 +2271,11 @@
       'id': 358,
       'caption': '''Enable the creation of roaming copies for <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> profile data''',
       'tags': ['local-data-access'],
-      'desc': '''If you enable this setting, the settings stored in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> profiles like bookmarks, autofill data, passwords, etc. will also be written to a file stored in the Roaming user profile folder or a location specified by the Administrator through the <ph name="ROAMING_PROFILE_LOCATION_POLICY_NAME">$1<ex>RoamingProfileLocation</ex></ph> policy. Enabling this policy disables cloud sync.
+      'desc': '''If you enable this setting, the settings stored in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> profiles like bookmarks, autofill data, passwords, etc. will also be written to a file stored in the Roaming user profile folder or a location specified by the Administrator through the <ph name="ROAMING_PROFILE_LOCATION_POLICY_NAME">RoamingProfileLocation</ph> policy. Enabling this policy disables cloud sync.
 
       If this policy is disabled or left not set only the regular local profiles will be used.
 
-      The <ph name="SYNC_DISABLED_POLICY_NAME">SyncDisabled</ph> policy disables all data synchronization, overriding RoamingProfileSupportEnabled.''',
+      The <ph name="SYNC_DISABLED_POLICY_NAME">SyncDisabled</ph> policy disables all data synchronization, overriding <ph name="ROAMING_PROFILE_SUPPORT_ENABLED_POLICY_NAME">RoamingProfileSupportEnabled</ph>.''',
       'label': '''Enable the creation of roaming copies for <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> profile data.''',
     },
     {
@@ -2293,7 +2293,7 @@
       'tags': ['local-data-access'],
       'desc': '''Configures the directory that <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will use for storing the roaming copy of the profiles.
 
-      If you set this policy, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will use the provided directory to store the roaming copy of the profiles if the <ph name="ROAMING_PROFILE_SUPPORT_ENABLED_POLICY_NAME">$1<ex>RoamingProfileSupportEnabled</ex></ph> policy has been enabled. If the <ph name="ROAMING_PROFILE_SUPPORT_ENABLED_POLICY_NAME">$1<ex>RoamingProfileSupportEnabled</ex></ph> policy is disabled or left unset the value stored in this policy is not used.
+      If you set this policy, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will use the provided directory to store the roaming copy of the profiles if the <ph name="ROAMING_PROFILE_SUPPORT_ENABLED_POLICY_NAME">RoamingProfileSupportEnabled</ph> policy has been enabled. If the <ph name="ROAMING_PROFILE_SUPPORT_ENABLED_POLICY_NAME">RoamingProfileSupportEnabled</ph> policy is disabled or left unset the value stored in this policy is not used.
 
       See https://www.chromium.org/administrators/policy-list-3/user-data-directory-variables for a list of variables that can be used.
 
diff --git a/components/policy/tools/generate_extension_admx.py b/components/policy/tools/generate_extension_admx.py
index dd5db82..cf03ff2 100755
--- a/components/policy/tools/generate_extension_admx.py
+++ b/components/policy/tools/generate_extension_admx.py
@@ -66,15 +66,15 @@
     self._BeginAdmlTemplate()
     self._BeginAdmxTemplate()
 
-    root_category_full_name = ('extension_' + self._extension_id)
+    root_category_name = 'extension'
 
     # Add a category element for the root
-    self._AddCategory(self._extension_name, root_category_full_name,
+    self._AddCategory(self._extension_name, root_category_name,
                       'Google:Cat_Google')
 
     properties = self._schema['properties']
     for policy_name, policy_schema in properties.items():
-      self._AddPolicy(policy_name, policy_schema, root_category_full_name,
+      self._AddPolicy(policy_name, policy_schema, root_category_name,
                       self._REGISTRY_KEY)
 
     return self._ToPrettyXml(self._admx_doc.toxml()), self._ToPrettyXml(
diff --git a/components/sync/android/javatests/src/org/chromium/components/sync/notifier/InvalidationPreferencesTest.java b/components/sync/android/javatests/src/org/chromium/components/sync/notifier/InvalidationPreferencesTest.java
index e53a8c9b..8bde9fbe 100644
--- a/components/sync/android/javatests/src/org/chromium/components/sync/notifier/InvalidationPreferencesTest.java
+++ b/components/sync/android/javatests/src/org/chromium/components/sync/notifier/InvalidationPreferencesTest.java
@@ -10,14 +10,15 @@
 import com.google.ipc.invalidation.external.client.types.ObjectId;
 
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.CollectionUtil;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.RetryOnFailure;
 
 import java.util.Arrays;
@@ -31,8 +32,13 @@
 @RunWith(BaseJUnit4ClassRunner.class)
 @RetryOnFailure
 public class InvalidationPreferencesTest {
+    @Before
+    public void setUp() {
+        // Make sure the SharedPreferences start out empty.
+        ContextUtils.getAppSharedPreferences().edit().clear().apply();
+    }
+
     @Test
-    @FlakyTest(message = "https://crbug.com/905233")
     @SmallTest
     @Feature({"Sync"})
     public void testReadMissingData() {
@@ -47,7 +53,6 @@
     }
 
     @Test
-    @FlakyTest(message = "https://crbug.com/905233")
     @SmallTest
     @Feature({"Sync"})
     public void testReadWriteAndReadData() {
diff --git a/components/sync/base/experiments.h b/components/sync/base/experiments.h
index 34e13d8..921acaa8 100644
--- a/components/sync/base/experiments.h
+++ b/components/sync/base/experiments.h
@@ -13,25 +13,17 @@
 
 const char kFaviconSyncTag[] = "favicon_sync";
 const char kPreCommitUpdateAvoidanceTag[] = "pre_commit_update_avoidance";
-const char kGCMInvalidationsTag[] = "gcm_invalidations";
 
 // A structure to hold the enable status of experimental sync features.
 struct Experiments {
-  Experiments()
-      : favicon_sync_limit(200),
-        // By default GCM channel is enabled:
-        gcm_invalidations_enabled(true) {}
+  Experiments() : favicon_sync_limit(200) {}
 
   bool Matches(const Experiments& rhs) {
-    return (favicon_sync_limit == rhs.favicon_sync_limit &&
-            gcm_invalidations_enabled == rhs.gcm_invalidations_enabled);
+    return favicon_sync_limit == rhs.favicon_sync_limit;
   }
 
   // The number of favicons that a client is permitted to sync.
   int favicon_sync_limit;
-
-  // Enable invalidations over GCM channel.
-  bool gcm_invalidations_enabled;
 };
 
 }  // namespace syncer
diff --git a/components/sync/base/model_type.h b/components/sync/base/model_type.h
index c4481f6a..9ac434e5 100644
--- a/components/sync/base/model_type.h
+++ b/components/sync/base/model_type.h
@@ -199,7 +199,7 @@
 #if BUILDFLAG(ENABLE_READING_LIST)
     "readingList",
 #endif
-    "userEvents",  "tabs"};
+    "tabs"};
 
 // Protocol types are those types that have actual protocol buffer
 // representations. This distinguishes them from Proxy types, which have no
@@ -238,7 +238,7 @@
 #if BUILDFLAG(ENABLE_READING_LIST)
                       READING_LIST,
 #endif
-                      USER_EVENTS, PROXY_TABS);
+                      PROXY_TABS);
 }
 
 constexpr bool IsUserSelectableType(ModelType model_type) {
diff --git a/components/sync/base/sync_prefs.cc b/components/sync/base/sync_prefs.cc
index 0a86c097..b7877201 100644
--- a/components/sync/base/sync_prefs.cc
+++ b/components/sync/base/sync_prefs.cc
@@ -25,7 +25,7 @@
 //   pref_groups_[EXTENSIONS] = { EXTENSION_SETTINGS }
 // etc.
 using PrefGroupsMap = std::map<ModelType, ModelTypeSet>;
-PrefGroupsMap ComputePrefGroups(bool user_events_separate_pref_group) {
+PrefGroupsMap ComputePrefGroups() {
   PrefGroupsMap pref_groups;
   pref_groups[APPS].Put(APP_NOTIFICATIONS);
   pref_groups[APPS].Put(APP_SETTINGS);
@@ -47,10 +47,7 @@
   pref_groups[TYPED_URLS].Put(SESSIONS);
   pref_groups[TYPED_URLS].Put(FAVICON_IMAGES);
   pref_groups[TYPED_URLS].Put(FAVICON_TRACKING);
-
-  if (!user_events_separate_pref_group) {
-    pref_groups[TYPED_URLS].Put(USER_EVENTS);
-  }
+  pref_groups[TYPED_URLS].Put(USER_EVENTS);
 
   pref_groups[PROXY_TABS].Put(SESSIONS);
   pref_groups[PROXY_TABS].Put(FAVICON_IMAGES);
@@ -262,8 +259,7 @@
 }
 
 ModelTypeSet SyncPrefs::GetPreferredDataTypes(
-    ModelTypeSet registered_types,
-    bool user_events_separate_pref_group) const {
+    ModelTypeSet registered_types) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (pref_service_->GetBoolean(prefs::kSyncKeepEverythingSynced)) {
@@ -276,16 +272,13 @@
       preferred_types.Put(type);
     }
   }
-  return ResolvePrefGroups(registered_types, preferred_types,
-                           user_events_separate_pref_group);
+  return ResolvePrefGroups(registered_types, preferred_types);
 }
 
 void SyncPrefs::SetPreferredDataTypes(ModelTypeSet registered_types,
-                                      ModelTypeSet preferred_types,
-                                      bool user_events_separate_pref_group) {
+                                      ModelTypeSet preferred_types) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  preferred_types = ResolvePrefGroups(registered_types, preferred_types,
-                                      user_events_separate_pref_group);
+  preferred_types = ResolvePrefGroups(registered_types, preferred_types);
   DCHECK(registered_types.HasAll(preferred_types));
   for (ModelType type : registered_types) {
     SetDataTypePreferred(type, preferred_types.Has(type));
@@ -474,13 +467,10 @@
 }
 
 // static
-ModelTypeSet SyncPrefs::ResolvePrefGroups(
-    ModelTypeSet registered_types,
-    ModelTypeSet types,
-    bool user_events_separate_pref_group) {
+ModelTypeSet SyncPrefs::ResolvePrefGroups(ModelTypeSet registered_types,
+                                          ModelTypeSet types) {
   ModelTypeSet types_with_groups = types;
-  for (const auto& pref_group :
-       ComputePrefGroups(user_events_separate_pref_group)) {
+  for (const auto& pref_group : ComputePrefGroups()) {
     if (types.Has(pref_group.first)) {
       types_with_groups.PutAll(pref_group.second);
     }
diff --git a/components/sync/base/sync_prefs.h b/components/sync/base/sync_prefs.h
index 0c0d66c2..03992e3 100644
--- a/components/sync/base/sync_prefs.h
+++ b/components/sync/base/sync_prefs.h
@@ -116,15 +116,7 @@
   // The returned set is guaranteed to be a subset of
   // |registered_types|.  Returns |registered_types| directly if
   // HasKeepEverythingSynced() is true.
-  // |user_events_separate_pref_group| is true when USER_EVENTS model type has
-  // a separate pref group instead of being bundled with the TYPED_URLS. This
-  // is used when Unified Consent is enabled.
-  //
-  // TODO(https://crbug.com/862983): |user_events_separate_pref_group| is only
-  // temporary and should removed once Unified Consent feature is is launched.
-  ModelTypeSet GetPreferredDataTypes(
-      ModelTypeSet registered_types,
-      bool user_events_separate_pref_group) const;
+  ModelTypeSet GetPreferredDataTypes(ModelTypeSet registered_types) const;
 
   // |preferred_types| should be a subset of |registered_types|.  All
   // types in |preferred_types| are marked preferred, and all types in
@@ -132,15 +124,8 @@
   // Changes are still made to the prefs even if
   // HasKeepEverythingSynced() is true, but won't be visible until
   // SetKeepEverythingSynced(false) is called.
-  // |user_events_separate_pref_group| is true when USER_EVENTS model type has
-  // a separate pref group instead of being bundled with the TYPED_URLS. This
-  // is used when Unified Consent is enabled.
-  //
-  // TODO(https://crbug.com/862983): |user_events_separate_pref_group| is only
-  // temporary and should removed once Unified Consent feature is is launched.
   void SetPreferredDataTypes(ModelTypeSet registered_types,
-                             ModelTypeSet preferred_types,
-                             bool user_events_separate_pref_group);
+                             ModelTypeSet preferred_types);
 
   // Whether Sync is forced off by enterprise policy. Note that this only covers
   // one out of two types of policy, "browser" policy. The second kind, "cloud"
@@ -221,8 +206,7 @@
   // (see |pref_groups_|), but as a subset of |registered_types|.
   // Exposed for testing.
   static ModelTypeSet ResolvePrefGroups(ModelTypeSet registered_types,
-                                        ModelTypeSet types,
-                                        bool user_events_separate_pref_group);
+                                        ModelTypeSet types);
 
  private:
   static void RegisterDataTypePreferredPref(
diff --git a/components/sync/base/sync_prefs_unittest.cc b/components/sync/base/sync_prefs_unittest.cc
index 1072ea14..2708f24d 100644
--- a/components/sync/base/sync_prefs_unittest.cc
+++ b/components/sync/base/sync_prefs_unittest.cc
@@ -118,26 +118,22 @@
 // Test that manipulate preferred data types.
 // -----------------------------------------------------------------------------
 
-class SyncPrefsDataTypesTest : public SyncPrefsTest,
-                               public testing::WithParamInterface<bool> {
+class SyncPrefsDataTypesTest : public SyncPrefsTest {
  protected:
-  SyncPrefsDataTypesTest() : user_events_separate_pref_group_(GetParam()) {}
+  SyncPrefsDataTypesTest() {}
 
   ModelTypeSet GetPreferredDataTypes(ModelTypeSet registered_types) {
-    return sync_prefs_->GetPreferredDataTypes(registered_types,
-                                              user_events_separate_pref_group_);
+    return sync_prefs_->GetPreferredDataTypes(registered_types);
   }
 
   void SetPreferredDataTypes(ModelTypeSet registered_types,
                              ModelTypeSet preferred_types) {
-    return sync_prefs_->SetPreferredDataTypes(registered_types, preferred_types,
-                                              user_events_separate_pref_group_);
+    return sync_prefs_->SetPreferredDataTypes(registered_types,
+                                              preferred_types);
   }
-
-  const bool user_events_separate_pref_group_;
 };
 
-TEST_P(SyncPrefsDataTypesTest, Basic) {
+TEST_F(SyncPrefsDataTypesTest, Basic) {
   EXPECT_FALSE(sync_prefs_->IsFirstSetupComplete());
   sync_prefs_->SetFirstSetupComplete();
   EXPECT_TRUE(sync_prefs_->IsFirstSetupComplete());
@@ -164,7 +160,7 @@
   EXPECT_EQ("token", sync_prefs_->GetEncryptionBootstrapToken());
 }
 
-TEST_P(SyncPrefsDataTypesTest, DefaultTypes) {
+TEST_F(SyncPrefsDataTypesTest, DefaultTypes) {
   sync_prefs_->SetKeepEverythingSynced(false);
 
   ModelTypeSet preferred_types = GetPreferredDataTypes(UserTypes());
@@ -201,7 +197,7 @@
   EXPECT_FALSE(preferred_types.Has(HISTORY_DELETE_DIRECTIVES));
 }
 
-TEST_P(SyncPrefsDataTypesTest, PreferredTypesKeepEverythingSynced) {
+TEST_F(SyncPrefsDataTypesTest, PreferredTypesKeepEverythingSynced) {
   EXPECT_TRUE(sync_prefs_->HasKeepEverythingSynced());
 
   const ModelTypeSet user_types = UserTypes();
@@ -215,7 +211,7 @@
   }
 }
 
-TEST_P(SyncPrefsDataTypesTest, PreferredTypesNotKeepEverythingSynced) {
+TEST_F(SyncPrefsDataTypesTest, PreferredTypesNotKeepEverythingSynced) {
   sync_prefs_->SetKeepEverythingSynced(false);
 
   const ModelTypeSet user_types = UserTypes();
@@ -250,9 +246,7 @@
       expected_preferred_types.Put(SESSIONS);
       expected_preferred_types.Put(FAVICON_IMAGES);
       expected_preferred_types.Put(FAVICON_TRACKING);
-      if (!user_events_separate_pref_group_) {
-        expected_preferred_types.Put(USER_EVENTS);
-      }
+      expected_preferred_types.Put(USER_EVENTS);
     }
     if (type == PROXY_TABS) {
       expected_preferred_types.Put(SESSIONS);
@@ -268,7 +262,7 @@
 }
 
 // Device info should always be enabled.
-TEST_P(SyncPrefsDataTypesTest, DeviceInfo) {
+TEST_F(SyncPrefsDataTypesTest, DeviceInfo) {
   EXPECT_TRUE(GetPreferredDataTypes(UserTypes()).Has(DEVICE_INFO));
   sync_prefs_->SetKeepEverythingSynced(true);
   EXPECT_TRUE(GetPreferredDataTypes(UserTypes()).Has(DEVICE_INFO));
@@ -281,7 +275,7 @@
 }
 
 // User Consents should always be enabled.
-TEST_P(SyncPrefsDataTypesTest, UserConsents) {
+TEST_F(SyncPrefsDataTypesTest, UserConsents) {
   EXPECT_TRUE(GetPreferredDataTypes(UserTypes()).Has(USER_CONSENTS));
   sync_prefs_->SetKeepEverythingSynced(true);
   EXPECT_TRUE(GetPreferredDataTypes(UserTypes()).Has(USER_CONSENTS));
@@ -293,10 +287,6 @@
   EXPECT_TRUE(GetPreferredDataTypes(UserTypes()).Has(USER_CONSENTS));
 }
 
-INSTANTIATE_TEST_CASE_P(,
-                        SyncPrefsDataTypesTest,
-                        ::testing::Values(false, true));
-
 }  // namespace
 
 }  // namespace syncer
diff --git a/components/sync/driver/data_type_manager_impl.cc b/components/sync/driver/data_type_manager_impl.cc
index 9379891..b139bb8 100644
--- a/components/sync/driver/data_type_manager_impl.cc
+++ b/components/sync/driver/data_type_manager_impl.cc
@@ -428,10 +428,6 @@
   ConfigureImpl(last_requested_types_, last_requested_context_);
 }
 
-void DataTypeManagerImpl::OnDownloadRetry() {
-  DCHECK_EQ(CONFIGURING, state_);
-}
-
 void DataTypeManagerImpl::DownloadReady(
     ModelTypeSet types_to_download,
     ModelTypeSet first_sync_types,
@@ -631,8 +627,6 @@
   params->ready_task =
       base::Bind(&DataTypeManagerImpl::DownloadReady,
                  weak_ptr_factory_.GetWeakPtr(), download_types_queue_.front());
-  params->retry_callback = base::Bind(&DataTypeManagerImpl::OnDownloadRetry,
-                                      weak_ptr_factory_.GetWeakPtr());
   params->is_sync_feature_enabled = last_requested_context_.storage_option ==
                                     ConfigureContext::STORAGE_ON_DISK;
 
diff --git a/components/sync/driver/data_type_manager_impl.h b/components/sync/driver/data_type_manager_impl.h
index 7ad2a47e..85b4676 100644
--- a/components/sync/driver/data_type_manager_impl.h
+++ b/components/sync/driver/data_type_manager_impl.h
@@ -154,9 +154,6 @@
                      ModelTypeSet first_sync_types,
                      ModelTypeSet failed_configuration_types);
 
-  // Notification from the SBH that download failed due to a transient
-  // error and it will be retried.
-  void OnDownloadRetry();
   void NotifyStart();
   void NotifyDone(const ConfigureResult& result);
 
diff --git a/components/sync/driver/fake_sync_client.cc b/components/sync/driver/fake_sync_client.cc
index b6c0b94..8795c7e 100644
--- a/components/sync/driver/fake_sync_client.cc
+++ b/components/sync/driver/fake_sync_client.cc
@@ -71,11 +71,10 @@
   return base::DoNothing();
 }
 
-DataTypeController::TypeVector FakeSyncClient::CreateDataTypeControllers(
-    LocalDeviceInfoProvider* local_device_info_provider) {
+DataTypeController::TypeVector FakeSyncClient::CreateDataTypeControllers() {
   DCHECK(factory_);
   return factory_->CreateCommonDataTypeControllers(
-      /*disabled_types=*/ModelTypeSet(), local_device_info_provider);
+      /*disabled_types=*/ModelTypeSet());
 }
 
 autofill::PersonalDataManager* FakeSyncClient::GetPersonalDataManager() {
diff --git a/components/sync/driver/fake_sync_client.h b/components/sync/driver/fake_sync_client.h
index ff38e989..d56973bc 100644
--- a/components/sync/driver/fake_sync_client.h
+++ b/components/sync/driver/fake_sync_client.h
@@ -34,8 +34,7 @@
   sync_sessions::SessionSyncService* GetSessionSyncService() override;
   bool HasPasswordStore() override;
   base::Closure GetPasswordStateChangedCallback() override;
-  DataTypeController::TypeVector CreateDataTypeControllers(
-      LocalDeviceInfoProvider* local_device_info_provider) override;
+  DataTypeController::TypeVector CreateDataTypeControllers() override;
   autofill::PersonalDataManager* GetPersonalDataManager() override;
   BookmarkUndoService* GetBookmarkUndoServiceIfExists() override;
   invalidation::InvalidationService* GetInvalidationService() override;
diff --git a/components/sync/driver/glue/sync_backend_host_core.cc b/components/sync/driver/glue/sync_backend_host_core.cc
index ce43193..e979aa45 100644
--- a/components/sync/driver/glue/sync_backend_host_core.cc
+++ b/components/sync/driver/glue/sync_backend_host_core.cc
@@ -169,8 +169,7 @@
   sync_manager_->ConfigureSyncer(
       reason, new_control_types, SyncManager::SyncFeatureState::INITIALIZING,
       base::Bind(&SyncBackendHostCore::DoInitialProcessControlTypes,
-                 weak_ptr_factory_.GetWeakPtr()),
-      base::Closure());
+                 weak_ptr_factory_.GetWeakPtr()));
 }
 
 void SyncBackendHostCore::OnConnectionStatusChange(ConnectionStatus status) {
@@ -484,22 +483,18 @@
     ModelTypeConfigurer::ConfigureParams params) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!params.ready_task.is_null());
-  DCHECK(!params.retry_callback.is_null());
 
   registrar_->ConfigureDataTypes(params.enabled_types, params.disabled_types);
 
   base::Closure chained_ready_task(base::Bind(
       &SyncBackendHostCore::DoFinishConfigureDataTypes,
       weak_ptr_factory_.GetWeakPtr(), params.to_download, params.ready_task));
-  base::Closure chained_retry_task(
-      base::Bind(&SyncBackendHostCore::DoRetryConfiguration,
-                 weak_ptr_factory_.GetWeakPtr(), params.retry_callback));
 
   sync_manager_->ConfigureSyncer(params.reason, params.to_download,
                                  params.is_sync_feature_enabled
                                      ? SyncManager::SyncFeatureState::ON
                                      : SyncManager::SyncFeatureState::OFF,
-                                 chained_ready_task, chained_retry_task);
+                                 chained_ready_task);
 }
 
 void SyncBackendHostCore::DoFinishConfigureDataTypes(
@@ -523,13 +518,6 @@
              failed_configuration_types, ready_task);
 }
 
-void SyncBackendHostCore::DoRetryConfiguration(
-    const base::Closure& retry_callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  host_.Call(FROM_HERE, &SyncBackendHostImpl::RetryConfigurationOnFrontendLoop,
-             retry_callback);
-}
-
 void SyncBackendHostCore::SendBufferedProtocolEventsAndEnableForwarding() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   forward_protocol_events_ = true;
diff --git a/components/sync/driver/glue/sync_backend_host_impl.cc b/components/sync/driver/glue/sync_backend_host_impl.cc
index e7ac8b950..d57396e 100644
--- a/components/sync/driver/glue/sync_backend_host_impl.cc
+++ b/components/sync/driver/glue/sync_backend_host_impl.cc
@@ -357,12 +357,6 @@
   }
 }
 
-void SyncBackendHostImpl::RetryConfigurationOnFrontendLoop(
-    const base::Closure& retry_callback) {
-  SDVLOG(1) << "Failed to complete configuration, informing of retry.";
-  retry_callback.Run();
-}
-
 void SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop(
     const SyncProtocolError& sync_error) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/components/sync/driver/glue/sync_backend_host_impl.h b/components/sync/driver/glue/sync_backend_host_impl.h
index 0c73b13..cc6eb373 100644
--- a/components/sync/driver/glue/sync_backend_host_impl.h
+++ b/components/sync/driver/glue/sync_backend_host_impl.h
@@ -173,11 +173,6 @@
   void HandleSyncCycleCompletedOnFrontendLoop(
       const SyncCycleSnapshot& snapshot);
 
-  // Called when the syncer failed to perform a configuration and will
-  // eventually retry. FinishingConfigurationOnFrontendLoop(..) will be called
-  // on successful completion.
-  void RetryConfigurationOnFrontendLoop(const base::Closure& retry_callback);
-
   // For convenience, checks if initialization state is INITIALIZED.
   bool initialized() const { return initialized_; }
 
diff --git a/components/sync/driver/glue/sync_backend_host_impl_unittest.cc b/components/sync/driver/glue/sync_backend_host_impl_unittest.cc
index 00343941..53623c0 100644
--- a/components/sync/driver/glue/sync_backend_host_impl_unittest.cc
+++ b/components/sync/driver/glue/sync_backend_host_impl_unittest.cc
@@ -267,8 +267,6 @@
     params.to_purge = Intersection(engine_types_, disabled_types);
     params.ready_task =
         base::Bind(&SyncEngineTest::DownloadReady, base::Unretained(this));
-    params.retry_callback =
-        base::Bind(&SyncEngineTest::OnDownloadRetry, base::Unretained(this));
 
     ModelTypeSet ready_types =
         Difference(params.enabled_types, params.to_download);
@@ -284,8 +282,6 @@
     std::move(quit_loop_).Run();
   }
 
-  void OnDownloadRetry() { NOTIMPLEMENTED(); }
-
   void SetEngineTypes(ModelTypeSet engine_types) {
     EXPECT_TRUE(engine_types_.Empty());
     engine_types_ = engine_types;
diff --git a/components/sync/driver/sync_api_component_factory.h b/components/sync/driver/sync_api_component_factory.h
index 10252a6c..ff21d048 100644
--- a/components/sync/driver/sync_api_component_factory.h
+++ b/components/sync/driver/sync_api_component_factory.h
@@ -63,11 +63,8 @@
   // Creates and returns enabled datatypes and their controllers.
   // |disabled_types| allows callers to prevent certain types from being
   // created (e.g. to honor command-line flags).
-  // TODO(crbug.com/895455): Remove |local_device_info_provider| once the
-  // migration to USS is completed.
   virtual DataTypeController::TypeVector CreateCommonDataTypeControllers(
-      ModelTypeSet disabled_types,
-      LocalDeviceInfoProvider* local_device_info_provider) = 0;
+      ModelTypeSet disabled_types) = 0;
 
   virtual std::unique_ptr<DataTypeManager> CreateDataTypeManager(
       ModelTypeSet initial_types,
diff --git a/components/sync/driver/sync_api_component_factory_mock.h b/components/sync/driver/sync_api_component_factory_mock.h
index 01325cf1..456ebaa 100644
--- a/components/sync/driver/sync_api_component_factory_mock.h
+++ b/components/sync/driver/sync_api_component_factory_mock.h
@@ -28,10 +28,8 @@
   SyncApiComponentFactoryMock();
   ~SyncApiComponentFactoryMock() override;
 
-  MOCK_METHOD2(CreateCommonDataTypeControllers,
-               DataTypeController::TypeVector(
-                   ModelTypeSet disabled_types,
-                   LocalDeviceInfoProvider* local_device_info_provider));
+  MOCK_METHOD1(CreateCommonDataTypeControllers,
+               DataTypeController::TypeVector(ModelTypeSet disabled_types));
   MOCK_METHOD6(CreateDataTypeManager,
                std::unique_ptr<DataTypeManager>(
                    ModelTypeSet,
diff --git a/components/sync/driver/sync_client.h b/components/sync/driver/sync_client.h
index a8aadec..aa267d70 100644
--- a/components/sync/driver/sync_client.h
+++ b/components/sync/driver/sync_client.h
@@ -44,7 +44,6 @@
 
 namespace syncer {
 
-class LocalDeviceInfoProvider;
 class ModelTypeStoreService;
 class SyncService;
 class SyncableService;
@@ -80,10 +79,7 @@
   virtual bool HasPasswordStore() = 0;
 
   // Returns a vector with all supported datatypes and their controllers.
-  // TODO(crbug.com/895455): Remove |local_device_info_provider| once the
-  // migration to USS is completed.
-  virtual DataTypeController::TypeVector CreateDataTypeControllers(
-      LocalDeviceInfoProvider* local_device_info_provider) = 0;
+  virtual DataTypeController::TypeVector CreateDataTypeControllers() = 0;
 
   // Returns a callback that will be invoked when password sync state has
   // potentially been changed.
diff --git a/components/sync/driver/sync_client_mock.h b/components/sync/driver/sync_client_mock.h
index 221e986..86b4811 100644
--- a/components/sync/driver/sync_client_mock.h
+++ b/components/sync/driver/sync_client_mock.h
@@ -25,9 +25,7 @@
   MOCK_METHOD0(GetHistoryService, history::HistoryService*());
   MOCK_METHOD0(HasPasswordStore, bool());
   MOCK_METHOD0(GetSessionSyncService, sync_sessions::SessionSyncService*());
-  MOCK_METHOD1(CreateDataTypeControllers,
-               DataTypeController::TypeVector(
-                   LocalDeviceInfoProvider* local_device_info_provider));
+  MOCK_METHOD0(CreateDataTypeControllers, DataTypeController::TypeVector());
   MOCK_METHOD0(GetPasswordStateChangedCallback, base::RepeatingClosure());
 
   MOCK_METHOD0(GetPersonalDataManager, autofill::PersonalDataManager*());
diff --git a/components/sync/driver/sync_driver_switches.cc b/components/sync/driver/sync_driver_switches.cc
index 901ef78f..c7a0899 100644
--- a/components/sync/driver/sync_driver_switches.cc
+++ b/components/sync/driver/sync_driver_switches.cc
@@ -124,10 +124,6 @@
 const base::Feature kSyncUSSPasswords{"SyncUSSPasswords",
                                       base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enable USS implementation of sessions.
-const base::Feature kSyncUSSSessions{"SyncUSSSessions",
-                                     base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enable USS implementation of autofill profile datatype.
 const base::Feature kSyncUSSAutofillProfile{"SyncUSSAutofillProfile",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/sync/driver/sync_driver_switches.h b/components/sync/driver/sync_driver_switches.h
index 1569886..e7c6e5e 100644
--- a/components/sync/driver/sync_driver_switches.h
+++ b/components/sync/driver/sync_driver_switches.h
@@ -47,7 +47,6 @@
 extern const base::Feature kSyncUserTranslationEvents;
 extern const base::Feature kSyncUSSBookmarks;
 extern const base::Feature kSyncUSSPasswords;
-extern const base::Feature kSyncUSSSessions;
 extern const base::Feature kSyncUSSAutofillProfile;
 extern const base::Feature kSyncUSSAutofillWalletData;
 extern const base::Feature kSyncUSSAutofillWalletMetadata;
diff --git a/components/sync/driver/sync_service_utils.cc b/components/sync/driver/sync_service_utils.cc
index 185d2bf..78b76dec 100644
--- a/components/sync/driver/sync_service_utils.cc
+++ b/components/sync/driver/sync_service_utils.cc
@@ -17,6 +17,7 @@
   // "everything" (i.e. the default setting). If a data type is missing there,
   // it must be because the user explicitly disabled it.
   if (!sync_service || sync_service->IsLocalSyncEnabled() ||
+      !sync_service->CanSyncFeatureStart() ||
       !sync_service->GetPreferredDataTypes().Has(type)) {
     return UploadState::NOT_ACTIVE;
   }
diff --git a/components/sync/driver/sync_service_utils_unittest.cc b/components/sync/driver/sync_service_utils_unittest.cc
index fd329314..2703b51 100644
--- a/components/sync/driver/sync_service_utils_unittest.cc
+++ b/components/sync/driver/sync_service_utils_unittest.cc
@@ -195,4 +195,28 @@
             GetUploadToGoogleState(&service, syncer::DEVICE_INFO));
 }
 
+TEST(SyncServiceUtilsTest, UploadToGoogleDisabledForSecondaryAccount) {
+  TestSyncService service;
+  service.SetDisableReasons(syncer::SyncService::DISABLE_REASON_NONE);
+  service.SetPreferredDataTypes(ProtocolTypes());
+  service.SetActiveDataTypes(ProtocolTypes());
+  service.SetTransportState(syncer::SyncService::TransportState::ACTIVE);
+  service.SetNonEmptyLastCycleSnapshot();
+
+  // Sanity check: Everything's looking good, so upload is considered active.
+  ASSERT_EQ(UploadState::ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+
+  // Mark the syncing account as non-primary. With this, only Sync-the-transport
+  // (not Sync-the-feature) can run.
+  service.SetIsAuthenticatedAccountPrimary(false);
+  ASSERT_FALSE(service.CanSyncFeatureStart());
+
+  // Upload should NOT be active now. Even though the data type is active, we're
+  // running in standalone transport mode, so we don't have consent for
+  // uploading.
+  EXPECT_EQ(UploadState::NOT_ACTIVE,
+            GetUploadToGoogleState(&service, syncer::BOOKMARKS));
+}
+
 }  // namespace syncer
diff --git a/components/sync/driver/sync_type_preference_provider.h b/components/sync/driver/sync_type_preference_provider.h
index 6ab1b3fb..8034818 100644
--- a/components/sync/driver/sync_type_preference_provider.h
+++ b/components/sync/driver/sync_type_preference_provider.h
@@ -11,7 +11,7 @@
 
 class SyncTypePreferenceProvider {
  public:
-  virtual ModelTypeSet GetPreferredDataTypes() const = 0;
+  virtual ModelTypeSet GetForcedDataTypes() const = 0;
 
  protected:
   virtual ~SyncTypePreferenceProvider() {}
diff --git a/components/sync/driver/sync_user_settings.h b/components/sync/driver/sync_user_settings.h
index 6ec0568..1943b1f4 100644
--- a/components/sync/driver/sync_user_settings.h
+++ b/components/sync/driver/sync_user_settings.h
@@ -20,6 +20,8 @@
 
   // Whether the user wants Sync to run, a.k.a. the Sync feature toggle in
   // settings. This maps to DISABLE_REASON_USER_CHOICE.
+  // NOTE: This is true by default, even if the user has never enabled Sync or
+  // isn't even signed in.
   virtual bool IsSyncRequested() const = 0;
   virtual void SetSyncRequested(bool requested) = 0;
 
@@ -30,18 +32,21 @@
 
   // Whether the initial Sync setup has been completed, meaning the user has
   // consented to Sync.
+  // NOTE: On Android and ChromeOS, this gets set automatically, so it doesn't
+  // really mean anything. See |browser_defaults::kSyncAutoStarts|.
   virtual bool IsFirstSetupComplete() const = 0;
   virtual void SetFirstSetupComplete() = 0;
 
   // The user's chosen data types. The "sync everything" flag means to sync all
-  // current and future data types. The "chosen types" are always a subset of
+  // current and future data types. If it is set, then GetChosenDataTypes() will
+  // always return "all types". The chosen types are always a subset of
   // syncer::UserSelectableTypes().
+  // NOTE: By default, GetChosenDataTypes() returns "all types", even if the
+  // user has never enabled Sync, or if only Sync-the-transport is running.
   virtual bool IsSyncEverythingEnabled() const = 0;
   virtual syncer::ModelTypeSet GetChosenDataTypes() const = 0;
   virtual void SetChosenDataTypes(bool sync_everything,
                                   syncer::ModelTypeSet types) = 0;
-  // TODO(crbug.com/884159): Should we also expose the "preferred" types here,
-  // which additionally include implied and forced types?
 
   // Encryption.
   virtual bool IsEncryptEverythingAllowed() const = 0;
diff --git a/components/sync/engine/fake_sync_manager.cc b/components/sync/engine/fake_sync_manager.cc
index 346173f3..13788efd 100644
--- a/components/sync/engine/fake_sync_manager.cc
+++ b/components/sync/engine/fake_sync_manager.cc
@@ -145,8 +145,7 @@
 void FakeSyncManager::ConfigureSyncer(ConfigureReason reason,
                                       ModelTypeSet to_download,
                                       SyncFeatureState sync_feature_state,
-                                      const base::Closure& ready_task,
-                                      const base::Closure& retry_task) {
+                                      const base::Closure& ready_task) {
   last_configure_reason_ = reason;
   ModelTypeSet success_types = to_download;
   success_types.RemoveAll(configure_fail_types_);
diff --git a/components/sync/engine/fake_sync_manager.h b/components/sync/engine/fake_sync_manager.h
index e9c3e31..67731215 100644
--- a/components/sync/engine/fake_sync_manager.h
+++ b/components/sync/engine/fake_sync_manager.h
@@ -89,8 +89,7 @@
   void ConfigureSyncer(ConfigureReason reason,
                        ModelTypeSet to_download,
                        SyncFeatureState sync_feature_state,
-                       const base::Closure& ready_task,
-                       const base::Closure& retry_task) override;
+                       const base::Closure& ready_task) override;
   void OnIncomingInvalidation(
       ModelType type,
       std::unique_ptr<InvalidationInterface> interface) override;
diff --git a/components/sync/engine/model_type_configurer.h b/components/sync/engine/model_type_configurer.h
index 0a37965..855d906 100644
--- a/components/sync/engine/model_type_configurer.h
+++ b/components/sync/engine/model_type_configurer.h
@@ -44,7 +44,6 @@
     // The awkward part is handling when SyncEngine calls ConfigureDataTypes on
     // itself to configure Nigori.
     base::Callback<void(ModelTypeSet, ModelTypeSet)> ready_task;
-    base::Closure retry_callback;
 
     // Whether full sync (or sync the feature) is enabled;
     bool is_sync_feature_enabled;
diff --git a/components/sync/engine/sync_manager.h b/components/sync/engine/sync_manager.h
index bfd87b2..ff57456 100644
--- a/components/sync/engine/sync_manager.h
+++ b/components/sync/engine/sync_manager.h
@@ -304,14 +304,10 @@
   // syncer will remain in CONFIGURATION_MODE until StartSyncingNormally is
   // called.
   // |ready_task| is invoked when the configuration completes.
-  // |retry_task| is invoked if the configuration job could not immediately
-  //              execute. |ready_task| will still be called when it eventually
-  //              does finish.
   virtual void ConfigureSyncer(ConfigureReason reason,
                                ModelTypeSet to_download,
                                SyncFeatureState sync_feature_state,
-                               const base::Closure& ready_task,
-                               const base::Closure& retry_task) = 0;
+                               const base::Closure& ready_task) = 0;
 
   // Inform the syncer of a change in the invalidator's state.
   virtual void SetInvalidatorEnabled(bool invalidator_enabled) = 0;
diff --git a/components/sync/engine_impl/model_type_worker.cc b/components/sync/engine_impl/model_type_worker.cc
index d5019b8e..1f93232 100644
--- a/components/sync/engine_impl/model_type_worker.cc
+++ b/components/sync/engine_impl/model_type_worker.cc
@@ -392,14 +392,13 @@
 }
 
 void ModelTypeWorker::ApplyPendingUpdates() {
-  if (BlockForEncryption())
+  if (!entries_pending_decryption_.empty())
     return;
+
   DVLOG(1) << ModelTypeToString(type_) << ": "
            << base::StringPrintf("Delivering %" PRIuS " applicable updates.",
                                  pending_updates_.size());
 
-  DCHECK(entries_pending_decryption_.empty());
-
   const bool contains_duplicate_server_ids =
       ContainsDuplicateServerID(pending_updates_);
   const bool contains_duplicate_client_tag_hashes =
@@ -572,11 +571,18 @@
       specifics = data->specifics;
     } else {
       DCHECK(data->specifics.has_encrypted());
-      if (!cryptographer_->CanDecrypt(data->specifics.encrypted()) ||
-          !DecryptSpecifics(*cryptographer_, data->specifics, &specifics)) {
+      if (!cryptographer_->CanDecrypt(data->specifics.encrypted())) {
         ++it;
         continue;
       }
+
+      if (!DecryptSpecifics(*cryptographer_, data->specifics, &specifics)) {
+        // Decryption error should be permanent (e.g. corrupt data), since
+        // CanDecrypt() above claims decryption keys are up-to-date. Let's
+        // ignore this update to avoid blocking other updates.
+        it = entries_pending_decryption_.erase(it);
+        continue;
+      }
     }
 
     UpdateResponseData decrypted_update;
diff --git a/components/sync/engine_impl/model_type_worker_unittest.cc b/components/sync/engine_impl/model_type_worker_unittest.cc
index 01fe5ed..8d4a582 100644
--- a/components/sync/engine_impl/model_type_worker_unittest.cc
+++ b/components/sync/engine_impl/model_type_worker_unittest.cc
@@ -192,18 +192,12 @@
     initial_state.mutable_progress_marker()->set_data_type_id(
         GetSpecificsFieldNumberFromModelType(model_type_));
 
-    InitializeWithState(model_type_, initial_state, UpdateResponseDataList());
+    InitializeWithState(model_type_, initial_state);
   }
 
   // Initializes with some existing data type state. Allows us to start
   // committing items right away.
   void NormalInitialize() {
-    InitializeWithPendingUpdates(UpdateResponseDataList());
-  }
-
-  // Initialize with some saved pending updates from the model thread.
-  void InitializeWithPendingUpdates(
-      const UpdateResponseDataList& initial_pending_updates) {
     ModelTypeState initial_state;
     initial_state.mutable_progress_marker()->set_data_type_id(
         GetSpecificsFieldNumberFromModelType(model_type_));
@@ -212,7 +206,7 @@
 
     initial_state.set_initial_sync_done(true);
 
-    InitializeWithState(model_type_, initial_state, initial_pending_updates);
+    InitializeWithState(model_type_, initial_state);
 
     nudge_handler()->ClearCounters();
   }
@@ -226,14 +220,11 @@
     ModelTypeState initial_state;
     initial_state.set_initial_sync_done(true);
 
-    InitializeWithState(USER_EVENTS, initial_state, UpdateResponseDataList());
+    InitializeWithState(USER_EVENTS, initial_state);
   }
 
   // Initialize with a custom initial ModelTypeState and pending updates.
-  void InitializeWithState(
-      const ModelType type,
-      const ModelTypeState& state,
-      const UpdateResponseDataList& initial_pending_updates) {
+  void InitializeWithState(const ModelType type, const ModelTypeState& state) {
     DCHECK(!worker());
 
     // We don't get to own this object. The |worker_| keeps a unique_ptr to it.
@@ -247,7 +238,6 @@
       cryptographer_copy = std::make_unique<Cryptographer>(*cryptographer_);
     }
 
-    // TODO(maxbogue): crbug.com/529498: Inject pending updates somehow.
     worker_ = std::make_unique<ModelTypeWorker>(
         type, state, !state.initial_sync_done(), std::move(cryptographer_copy),
         PassphraseType::IMPLICIT_PASSPHRASE, &mock_nudge_handler_,
@@ -1109,9 +1099,12 @@
   AddPendingKey();
   EXPECT_EQ(0U, processor()->GetNumUpdateResponses());
 
-  // Update progress marker, should be blocked.
-  server()->SetProgressMarkerToken("token2");
-  DeliverRawUpdates(SyncEntityList());
+  // Receive an encrypted update with that new key, which we can't access.
+  SetUpdateEncryptionFilter(1);
+  TriggerUpdateFromServer(10, kTag1, kValue1);
+
+  // At this point, the cryptographer does not have access to the key, so the
+  // updates will be undecryptable. This should block all updates.
   EXPECT_EQ(0U, processor()->GetNumUpdateResponses());
 
   // Update local cryptographer, verify everything is pushed to processor.
@@ -1268,7 +1261,7 @@
   // Receive a new foreign encryption key that we can't decrypt.
   AddPendingKey();
 
-  // Receive an encrypted with that new key, which we can't access.
+  // Receive an encrypted update with that new key, which we can't access.
   SetUpdateEncryptionFilter(1);
   TriggerUpdateFromServer(10, kTag1, kValue1);
 
@@ -1286,71 +1279,6 @@
   EXPECT_EQ(GetLocalCryptographerKeyName(), update.encryption_key_name);
 }
 
-// Test decryption of pending updates saved across a restart.
-TEST_F(ModelTypeWorkerTest, RestorePendingEntries) {
-  // Create a fake pending update.
-  EntityData entity;
-  entity.client_tag_hash = GenerateTagHash(kTag1);
-  entity.id = "SomeID";
-  entity.creation_time = Time::UnixEpoch() + TimeDelta::FromSeconds(10);
-  entity.modification_time = Time::UnixEpoch() + TimeDelta::FromSeconds(11);
-  entity.non_unique_name = "encrypted";
-  entity.specifics = GenerateSpecifics(kTag1, kValue1);
-  EncryptUpdate(GetNthKeyParams(1), &(entity.specifics));
-
-  UpdateResponseData update;
-  update.entity = entity.PassToPtr();
-  update.response_version = 100;
-
-  // Inject the update during CommitQueue initialization.
-  InitializeWithPendingUpdates({update});
-
-  // Update will be undecryptable at first.
-  EXPECT_EQ(0U, processor()->GetNumUpdateResponses());
-  EXPECT_FALSE(processor()->HasUpdateResponse(kHash1));
-
-  // Update the cryptographer so it can decrypt that update.
-  AddPendingKey();
-  DecryptPendingKey();
-
-  // Verify the item gets decrypted and sent back to the model thread.
-  // TODO(maxbogue): crbug.com/529498: Uncomment when pending updates are
-  // handled by the worker again.
-  // ASSERT_TRUE(processor()->HasUpdateResponse(kHash1));
-}
-
-// Test decryption of pending updates saved across a restart. This test
-// differs from the previous one in that the restored updates can be decrypted
-// immediately after the CommitQueue is constructed.
-TEST_F(ModelTypeWorkerTest, RestoreApplicableEntries) {
-  // Update the cryptographer so it can decrypt that update.
-  AddPendingKey();
-  DecryptPendingKey();
-
-  // Create a fake pending update.
-  EntityData entity;
-  entity.client_tag_hash = GenerateTagHash(kTag1);
-  entity.id = "SomeID";
-  entity.creation_time = Time::UnixEpoch() + TimeDelta::FromSeconds(10);
-  entity.modification_time = Time::UnixEpoch() + TimeDelta::FromSeconds(11);
-  entity.non_unique_name = "encrypted";
-
-  entity.specifics = GenerateSpecifics(kTag1, kValue1);
-  EncryptUpdate(GetNthKeyParams(1), &(entity.specifics));
-
-  UpdateResponseData update;
-  update.entity = entity.PassToPtr();
-  update.response_version = 100;
-
-  // Inject the update during CommitQueue initialization.
-  InitializeWithPendingUpdates({update});
-
-  // Verify the item gets decrypted and sent back to the model thread.
-  // TODO(maxbogue): crbug.com/529498: Uncomment when pending updates are
-  // handled by the worker again.
-  // ASSERT_TRUE(processor()->HasUpdateResponse(kHash1));
-}
-
 // Verify that corrupted encrypted updates don't cause crashes.
 TEST_F(ModelTypeWorkerTest, ReceiveCorruptEncryption) {
   // Initialize the worker with basic encryption state.
@@ -1802,7 +1730,7 @@
   sync_pb::EntitySpecifics encrypted_specifics =
       EncryptPasswordSpecifics(GetNthKeyParams(1), unencrypted_password);
 
-  // Receive an encrypted with that new key, which we can't access.
+  // Receive an encrypted update with that new key, which we can't access.
   SyncEntity entity = server()->UpdateFromServer(
       /*version_offset=*/10, kHash1, encrypted_specifics);
   worker()->ProcessGetUpdatesResponse(server()->GetProgress(),
diff --git a/components/sync/engine_impl/sync_manager_impl.cc b/components/sync/engine_impl/sync_manager_impl.cc
index 6495e11..0cff5d8 100644
--- a/components/sync/engine_impl/sync_manager_impl.cc
+++ b/components/sync/engine_impl/sync_manager_impl.cc
@@ -169,8 +169,7 @@
 void SyncManagerImpl::ConfigureSyncer(ConfigureReason reason,
                                       ModelTypeSet to_download,
                                       SyncFeatureState sync_feature_state,
-                                      const base::Closure& ready_task,
-                                      const base::Closure& retry_task) {
+                                      const base::Closure& ready_task) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!ready_task.is_null());
   DCHECK(initialized_);
@@ -183,7 +182,7 @@
            << "\n\t"
            << "types to download: " << ModelTypeSetToString(to_download);
   ConfigurationParams params(GetOriginFromReason(reason), to_download,
-                             ready_task, retry_task);
+                             ready_task);
 
   scheduler_->Start(SyncScheduler::CONFIGURATION_MODE, base::Time());
   scheduler_->ScheduleConfiguration(params);
@@ -926,17 +925,6 @@
     // know about this.
   }
 
-  ReadNode gcm_invalidations_node(&trans);
-  if (gcm_invalidations_node.InitByClientTagLookup(
-          EXPERIMENTS, kGCMInvalidationsTag) == BaseNode::INIT_OK) {
-    const sync_pb::GcmInvalidationsFlags& gcm_invalidations =
-        gcm_invalidations_node.GetExperimentsSpecifics().gcm_invalidations();
-    if (gcm_invalidations.has_enabled()) {
-      experiments->gcm_invalidations_enabled = gcm_invalidations.enabled();
-      found_experiment = true;
-    }
-  }
-
   return found_experiment;
 }
 
diff --git a/components/sync/engine_impl/sync_manager_impl.h b/components/sync/engine_impl/sync_manager_impl.h
index e77d52a..ef78b26 100644
--- a/components/sync/engine_impl/sync_manager_impl.h
+++ b/components/sync/engine_impl/sync_manager_impl.h
@@ -82,8 +82,7 @@
   void ConfigureSyncer(ConfigureReason reason,
                        ModelTypeSet to_download,
                        SyncFeatureState sync_feature_state,
-                       const base::Closure& ready_task,
-                       const base::Closure& retry_task) override;
+                       const base::Closure& ready_task) override;
   void SetInvalidatorEnabled(bool invalidator_enabled) override;
   void OnIncomingInvalidation(
       ModelType type,
diff --git a/components/sync/engine_impl/sync_manager_impl_unittest.cc b/components/sync/engine_impl/sync_manager_impl_unittest.cc
index 66b588d..50482e2 100644
--- a/components/sync/engine_impl/sync_manager_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_manager_impl_unittest.cc
@@ -2539,15 +2539,12 @@
   EXPECT_CALL(*scheduler(), ScheduleConfiguration(_))
       .WillOnce(SaveArg<0>(&params));
 
-  CallbackCounter ready_task_counter, retry_task_counter;
+  CallbackCounter ready_task_counter;
   sync_manager_.ConfigureSyncer(
       reason, types_to_download, SyncManager::SyncFeatureState::ON,
       base::Bind(&CallbackCounter::Callback,
-                 base::Unretained(&ready_task_counter)),
-      base::Bind(&CallbackCounter::Callback,
-                 base::Unretained(&retry_task_counter)));
+                 base::Unretained(&ready_task_counter)));
   EXPECT_EQ(0, ready_task_counter.times_called());
-  EXPECT_EQ(0, retry_task_counter.times_called());
   EXPECT_EQ(sync_pb::SyncEnums::RECONFIGURATION, params.origin);
   EXPECT_EQ(types_to_download, params.types_to_download);
 }
diff --git a/components/sync/engine_impl/sync_scheduler.h b/components/sync/engine_impl/sync_scheduler.h
index 2b509b7..8fdb1ab 100644
--- a/components/sync/engine_impl/sync_scheduler.h
+++ b/components/sync/engine_impl/sync_scheduler.h
@@ -26,8 +26,7 @@
   ConfigurationParams();
   ConfigurationParams(sync_pb::SyncEnums::GetUpdatesOrigin origin,
                       ModelTypeSet types_to_download,
-                      const base::Closure& ready_task,
-                      const base::Closure& retry_task);
+                      const base::Closure& ready_task);
   ConfigurationParams(const ConfigurationParams& other);
   ~ConfigurationParams();
 
@@ -37,8 +36,6 @@
   ModelTypeSet types_to_download;
   // Callback to invoke on configuration completion.
   base::Closure ready_task;
-  // Callback to invoke on configuration failure.
-  base::Closure retry_task;
 };
 
 struct ClearParams {
diff --git a/components/sync/engine_impl/sync_scheduler_impl.cc b/components/sync/engine_impl/sync_scheduler_impl.cc
index 71a2a18..5dbcd1cd 100644
--- a/components/sync/engine_impl/sync_scheduler_impl.cc
+++ b/components/sync/engine_impl/sync_scheduler_impl.cc
@@ -84,14 +84,6 @@
   return (error.action != UNKNOWN_ACTION);
 }
 
-void RunAndReset(base::Closure* task) {
-  DCHECK(task);
-  if (task->is_null())
-    return;
-  task->Run();
-  task->Reset();
-}
-
 #define ENUM_CASE(x) \
   case x:            \
     return #x;       \
@@ -104,12 +96,10 @@
 ConfigurationParams::ConfigurationParams(
     sync_pb::SyncEnums::GetUpdatesOrigin origin,
     ModelTypeSet types_to_download,
-    const base::Closure& ready_task,
-    const base::Closure& retry_task)
+    const base::Closure& ready_task)
     : origin(origin),
       types_to_download(types_to_download),
-      ready_task(ready_task),
-      retry_task(retry_task) {
+      ready_task(ready_task) {
   DCHECK(!ready_task.is_null());
 }
 ConfigurationParams::ConfigurationParams(const ConfigurationParams& other) =
@@ -495,7 +485,6 @@
 
   if (!CanRunJobNow(priority)) {
     SDVLOG(2) << "Unable to run configure job right now.";
-    RunAndReset(&pending_configure_params_->retry_task);
     return;
   }
 
@@ -516,8 +505,6 @@
     HandleFailure(cycle.status_controller().model_neutral_state());
     // Sync cycle might receive response from server that causes scheduler to
     // stop and draws pending_configure_params_ invalid.
-    if (started_)
-      RunAndReset(&pending_configure_params_->retry_task);
   }
 }
 
diff --git a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
index e98fcd4a..9a45bf4 100644
--- a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
@@ -403,15 +403,12 @@
   StartSyncConfiguration();
 
   CallbackCounter ready_counter;
-  CallbackCounter retry_counter;
   ConfigurationParams params(
       sync_pb::SyncEnums::RECONFIGURATION, model_types,
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
+      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)));
   scheduler()->ScheduleConfiguration(params);
   PumpLoop();
   ASSERT_EQ(1, ready_counter.times_called());
-  ASSERT_EQ(0, retry_counter.times_called());
 }
 
 // Simulate a failure and make sure the config request is retried.
@@ -431,21 +428,17 @@
                       RecordSyncShare(&times, false)));
 
   CallbackCounter ready_counter;
-  CallbackCounter retry_counter;
   ConfigurationParams params(
       sync_pb::SyncEnums::RECONFIGURATION, model_types,
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
+      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)));
   scheduler()->ScheduleConfiguration(params);
   RunLoop();
   ASSERT_EQ(0, ready_counter.times_called());
-  ASSERT_EQ(1, retry_counter.times_called());
 
   // RunLoop() will trigger TryCanaryJob which will retry configuration.
   // Since retry_task was already called it shouldn't be called again.
   RunLoop();
   ASSERT_EQ(0, ready_counter.times_called());
-  ASSERT_EQ(1, retry_counter.times_called());
 
   Mock::VerifyAndClearExpectations(syncer());
 
@@ -476,15 +469,12 @@
                       RecordSyncShare(&times, false)));
 
   CallbackCounter ready_counter;
-  CallbackCounter retry_counter;
   ConfigurationParams params(
       sync_pb::SyncEnums::RECONFIGURATION, model_types,
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
+      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)));
   scheduler()->ScheduleConfiguration(params);
   PumpLoop();
   ASSERT_EQ(0, ready_counter.times_called());
-  ASSERT_EQ(0, retry_counter.times_called());
 }
 
 // Verify that in the absence of valid auth token the command will fail.
@@ -497,15 +487,12 @@
   StartSyncConfiguration();
 
   CallbackCounter ready_counter;
-  CallbackCounter retry_counter;
   ConfigurationParams params(
       sync_pb::SyncEnums::RECONFIGURATION, model_types,
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
+      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)));
   scheduler()->ScheduleConfiguration(params);
   PumpLoop();
   ASSERT_EQ(0, ready_counter.times_called());
-  ASSERT_EQ(1, retry_counter.times_called());
 }
 
 // Verify that in the absence of valid auth token the command will pass if local
@@ -524,15 +511,12 @@
   StartSyncConfiguration();
 
   CallbackCounter ready_counter;
-  CallbackCounter retry_counter;
   ConfigurationParams params(
       sync_pb::SyncEnums::RECONFIGURATION, model_types,
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
+      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)));
   scheduler()->ScheduleConfiguration(params);
   PumpLoop();
   ASSERT_EQ(1, ready_counter.times_called());
-  ASSERT_EQ(0, retry_counter.times_called());
 }
 
 // Issue a nudge when the config has failed. Make sure both the config and
@@ -551,15 +535,12 @@
       .WillOnce(DoAll(Invoke(test_util::SimulateConfigureFailed),
                       RecordSyncShare(&times, false)));
   CallbackCounter ready_counter;
-  CallbackCounter retry_counter;
   ConfigurationParams params(
       sync_pb::SyncEnums::RECONFIGURATION, model_types,
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
+      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)));
   scheduler()->ScheduleConfiguration(params);
   RunLoop();
   ASSERT_EQ(0, ready_counter.times_called());
-  ASSERT_EQ(1, retry_counter.times_called());
   Mock::VerifyAndClearExpectations(syncer());
 
   // Ask for a nudge while dealing with repeated configure failure.
@@ -836,15 +817,12 @@
   StartSyncConfiguration();
 
   CallbackCounter ready_counter;
-  CallbackCounter retry_counter;
   ConfigurationParams params(
       sync_pb::SyncEnums::RECONFIGURATION, types,
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
+      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)));
   scheduler()->ScheduleConfiguration(params);
   PumpLoop();
   ASSERT_EQ(0, ready_counter.times_called());
-  ASSERT_EQ(1, retry_counter.times_called());
 }
 
 TEST_F(SyncSchedulerImplTest, ThrottlingExpiresFromPoll) {
@@ -920,15 +898,12 @@
   StartSyncConfiguration();
 
   CallbackCounter ready_counter;
-  CallbackCounter retry_counter;
   ConfigurationParams params(
       sync_pb::SyncEnums::RECONFIGURATION, types,
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
+      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)));
   scheduler()->ScheduleConfiguration(params);
   PumpLoop();
   EXPECT_EQ(0, ready_counter.times_called());
-  EXPECT_EQ(1, retry_counter.times_called());
   EXPECT_TRUE(scheduler()->IsGlobalThrottle());
 
   RunLoop();
@@ -1253,15 +1228,12 @@
                       RecordSyncShare(&times, true)))
       .RetiresOnSaturation();
   CallbackCounter ready_counter;
-  CallbackCounter retry_counter;
   ConfigurationParams params(
       sync_pb::SyncEnums::RECONFIGURATION, config_types,
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
+      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)));
   scheduler()->ScheduleConfiguration(params);
   RunLoop();
   ASSERT_EQ(1, ready_counter.times_called());
-  ASSERT_EQ(0, retry_counter.times_called());
 
   Mock::VerifyAndClearExpectations(syncer());
 
@@ -1345,11 +1317,9 @@
 
   ModelTypeSet types(THEMES);
   CallbackCounter ready_counter;
-  CallbackCounter retry_counter;
   ConfigurationParams params(
       sync_pb::SyncEnums::RECONFIGURATION, types,
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
+      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)));
   scheduler()->ScheduleConfiguration(params);
   RunLoop();
 
@@ -1394,15 +1364,12 @@
   StartSyncConfiguration();
 
   CallbackCounter ready_counter;
-  CallbackCounter retry_counter;
   ConfigurationParams params(
       sync_pb::SyncEnums::RECONFIGURATION, types,
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
+      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)));
   scheduler()->ScheduleConfiguration(params);
   PumpLoop();
   ASSERT_EQ(0, ready_counter.times_called());
-  ASSERT_EQ(1, retry_counter.times_called());
 }
 
 // Test that backoff is shaping traffic properly with consecutive errors.
@@ -1653,11 +1620,9 @@
 
   ModelTypeSet model_types(THEMES);
   CallbackCounter ready_counter;
-  CallbackCounter retry_counter;
   ConfigurationParams params(
       sync_pb::SyncEnums::RECONFIGURATION, model_types,
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
-      base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
+      base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)));
   scheduler()->ScheduleConfiguration(params);
 
   scheduler()->OnConnectionStatusChange(
diff --git a/components/sync/protocol/experiments_specifics.proto b/components/sync/protocol/experiments_specifics.proto
index c71c5eb..039f8b2 100644
--- a/components/sync/protocol/experiments_specifics.proto
+++ b/components/sync/protocol/experiments_specifics.proto
@@ -74,6 +74,7 @@
   optional GcmChannelFlags gcm_channel = 6;
   // No longer used as of M43.
   optional EnhancedBookmarksFlags obsolete_enhanced_bookmarks = 7;
+  // No longer used as of M72.
   optional GcmInvalidationsFlags gcm_invalidations = 8;
   // No longer used as of M51.
   optional WalletSyncFlags obsolete_wallet_sync = 9;
diff --git a/components/sync_sessions/BUILD.gn b/components/sync_sessions/BUILD.gn
index 57f9057..a653ad2d 100644
--- a/components/sync_sessions/BUILD.gn
+++ b/components/sync_sessions/BUILD.gn
@@ -4,8 +4,6 @@
 
 static_library("sync_sessions") {
   sources = [
-    "abstract_sessions_sync_manager.cc",
-    "abstract_sessions_sync_manager.h",
     "favicon_cache.cc",
     "favicon_cache.h",
     "local_session_event_handler_impl.cc",
@@ -17,8 +15,6 @@
     "open_tabs_ui_delegate.h",
     "open_tabs_ui_delegate_impl.cc",
     "open_tabs_ui_delegate_impl.h",
-    "session_data_type_controller.cc",
-    "session_data_type_controller.h",
     "session_model_type_controller.cc",
     "session_model_type_controller.h",
     "session_store.cc",
@@ -31,8 +27,6 @@
     "session_sync_service.h",
     "sessions_global_id_mapper.cc",
     "sessions_global_id_mapper.h",
-    "sessions_sync_manager.cc",
-    "sessions_sync_manager.h",
     "sync_sessions_client.cc",
     "sync_sessions_client.h",
     "synced_session.cc",
@@ -103,11 +97,9 @@
     "local_session_event_handler_impl_unittest.cc",
     "lost_navigations_recorder_unittest.cc",
     "open_tabs_ui_delegate_impl_unittest.cc",
-    "session_data_type_controller_unittest.cc",
     "session_store_unittest.cc",
     "session_sync_bridge_unittest.cc",
     "sessions_global_id_mapper_unittest.cc",
-    "sessions_sync_manager_unittest.cc",
     "synced_session_tracker_unittest.cc",
     "synced_session_unittest.cc",
     "tab_node_pool_unittest.cc",
diff --git a/components/sync_sessions/abstract_sessions_sync_manager.cc b/components/sync_sessions/abstract_sessions_sync_manager.cc
deleted file mode 100644
index a022ccc..0000000
--- a/components/sync_sessions/abstract_sessions_sync_manager.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// 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 "components/sync_sessions/abstract_sessions_sync_manager.h"
-
-namespace sync_sessions {
-
-AbstractSessionsSyncManager::AbstractSessionsSyncManager() = default;
-
-AbstractSessionsSyncManager::~AbstractSessionsSyncManager() = default;
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/abstract_sessions_sync_manager.h b/components/sync_sessions/abstract_sessions_sync_manager.h
deleted file mode 100644
index 91a0dcd5..0000000
--- a/components/sync_sessions/abstract_sessions_sync_manager.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// 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 COMPONENTS_SYNC_SESSIONS_ABSTRACT_SESSIONS_SYNC_MANAGER_H_
-#define COMPONENTS_SYNC_SESSIONS_ABSTRACT_SESSIONS_SYNC_MANAGER_H_
-
-#include "base/macros.h"
-
-namespace syncer {
-class ModelTypeSyncBridge;
-class SyncableService;
-}  // namespace syncer
-
-namespace sync_sessions {
-
-class FaviconCache;
-class OpenTabsUIDelegate;
-class SessionsGlobalIdMapper;
-
-// TODO(crbug.com/895455): Remove this interface once the migration to USS
-// is completed and the old code removed.
-class AbstractSessionsSyncManager {
- public:
-  AbstractSessionsSyncManager();
-  virtual ~AbstractSessionsSyncManager();
-
-  virtual void ScheduleGarbageCollection() = 0;
-  virtual FaviconCache* GetFaviconCache() = 0;
-  virtual SessionsGlobalIdMapper* GetGlobalIdMapper() = 0;
-  virtual OpenTabsUIDelegate* GetOpenTabsUIDelegate() = 0;
-  // Exactly one of the two below returns nullptr.
-  virtual syncer::SyncableService* GetSyncableService() = 0;
-  virtual syncer::ModelTypeSyncBridge* GetModelTypeSyncBridge() = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AbstractSessionsSyncManager);
-};
-
-}  // namespace sync_sessions
-
-#endif  // COMPONENTS_SYNC_SESSIONS_ABSTRACT_SESSIONS_SYNC_MANAGER_H_
diff --git a/components/sync_sessions/lost_navigations_recorder_unittest.cc b/components/sync_sessions/lost_navigations_recorder_unittest.cc
index 4774e9d..856fd9c 100644
--- a/components/sync_sessions/lost_navigations_recorder_unittest.cc
+++ b/components/sync_sessions/lost_navigations_recorder_unittest.cc
@@ -16,7 +16,6 @@
 #include "components/sync/syncable/syncable_write_transaction.h"
 #include "components/sync/test/engine/test_directory_setter_upper.h"
 #include "components/sync/test/engine/test_id_factory.h"
-#include "components/sync_sessions/sessions_sync_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using syncer::syncable::Entry;
diff --git a/components/sync_sessions/session_data_type_controller.cc b/components/sync_sessions/session_data_type_controller.cc
deleted file mode 100644
index be11c200..0000000
--- a/components/sync_sessions/session_data_type_controller.cc
+++ /dev/null
@@ -1,66 +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 "components/sync_sessions/session_data_type_controller.h"
-
-#include <set>
-
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "components/prefs/pref_service.h"
-#include "components/sync/driver/sync_client.h"
-
-namespace sync_sessions {
-
-SessionDataTypeController::SessionDataTypeController(
-    const base::Closure& dump_stack,
-    syncer::SyncClient* sync_client,
-    syncer::LocalDeviceInfoProvider* local_device,
-    const char* history_disabled_pref_name)
-    : AsyncDirectoryTypeController(syncer::SESSIONS,
-                                   dump_stack,
-                                   sync_client,
-                                   syncer::GROUP_UI,
-                                   base::SequencedTaskRunnerHandle::Get()),
-      sync_client_(sync_client),
-      local_device_(local_device),
-      history_disabled_pref_name_(history_disabled_pref_name) {
-  DCHECK(local_device_);
-  pref_registrar_.Init(sync_client_->GetPrefService());
-  pref_registrar_.Add(
-      history_disabled_pref_name_,
-      base::Bind(&SessionDataTypeController::OnSavingBrowserHistoryPrefChanged,
-                 base::AsWeakPtr(this)));
-}
-
-SessionDataTypeController::~SessionDataTypeController() {}
-
-bool SessionDataTypeController::StartModels() {
-  DCHECK(CalledOnValidThread());
-  DCHECK(local_device_->GetLocalDeviceInfo());
-  return true;
-}
-
-bool SessionDataTypeController::ReadyForStart() const {
-  DCHECK(CalledOnValidThread());
-  return !sync_client_->GetPrefService()->GetBoolean(
-      history_disabled_pref_name_);
-}
-
-void SessionDataTypeController::OnSavingBrowserHistoryPrefChanged() {
-  DCHECK(CalledOnValidThread());
-  if (sync_client_->GetPrefService()->GetBoolean(history_disabled_pref_name_)) {
-    // If history and tabs persistence is turned off then generate an
-    // unrecoverable error. SESSIONS won't be a registered type on the next
-    // Chrome restart.
-    if (state() != NOT_RUNNING && state() != STOPPING) {
-      syncer::SyncError error(
-          FROM_HERE, syncer::SyncError::DATATYPE_POLICY_ERROR,
-          "History and tab saving is now disabled by policy.",
-          syncer::SESSIONS);
-      CreateErrorHandler()->OnUnrecoverableError(error);
-    }
-  }
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/session_data_type_controller.h b/components/sync_sessions/session_data_type_controller.h
deleted file mode 100644
index a763f3f..0000000
--- a/components/sync_sessions/session_data_type_controller.h
+++ /dev/null
@@ -1,48 +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 COMPONENTS_SYNC_SESSIONS_SESSION_DATA_TYPE_CONTROLLER_H_
-#define COMPONENTS_SYNC_SESSIONS_SESSION_DATA_TYPE_CONTROLLER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "components/prefs/pref_change_registrar.h"
-#include "components/sync/device_info/local_device_info_provider.h"
-#include "components/sync/driver/async_directory_type_controller.h"
-
-namespace sync_sessions {
-
-// Overrides StartModels to wait for the local device info to become available.
-class SessionDataTypeController : public syncer::AsyncDirectoryTypeController {
- public:
-  // |dump_stack| is called when an unrecoverable error occurs.
-  SessionDataTypeController(const base::Closure& dump_stack,
-                            syncer::SyncClient* sync_client,
-                            syncer::LocalDeviceInfoProvider* local_device,
-                            const char* history_disabled_pref_name);
-  ~SessionDataTypeController() override;
-
-  // AsyncDirectoryTypeController implementation.
-  bool StartModels() override;
-  bool ReadyForStart() const override;
-
- private:
-  void OnSavingBrowserHistoryPrefChanged();
-
-  syncer::SyncClient* const sync_client_;
-
-  syncer::LocalDeviceInfoProvider* const local_device_;
-
-  // Name of the pref that indicates whether saving history is disabled.
-  const char* history_disabled_pref_name_;
-
-  PrefChangeRegistrar pref_registrar_;
-
-  DISALLOW_COPY_AND_ASSIGN(SessionDataTypeController);
-};
-
-}  // namespace sync_sessions
-
-#endif  // COMPONENTS_SYNC_SESSIONS_SESSION_DATA_TYPE_CONTROLLER_H_
diff --git a/components/sync_sessions/session_data_type_controller_unittest.cc b/components/sync_sessions/session_data_type_controller_unittest.cc
deleted file mode 100644
index f7f22c8..0000000
--- a/components/sync_sessions/session_data_type_controller_unittest.cc
+++ /dev/null
@@ -1,119 +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 "components/sync_sessions/session_data_type_controller.h"
-
-#include <set>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/sync/device_info/local_device_info_provider_mock.h"
-#include "components/sync/driver/configure_context.h"
-#include "components/sync/driver/fake_sync_client.h"
-#include "components/sync/driver/sync_api_component_factory_mock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using syncer::LocalDeviceInfoProviderMock;
-
-namespace sync_sessions {
-
-namespace {
-
-const char* kSavingBrowserHistoryDisabled = "history_disabled";
-
-class SessionDataTypeControllerTest : public testing::Test,
-                                      public syncer::FakeSyncClient {
- public:
-  SessionDataTypeControllerTest()
-      : syncer::FakeSyncClient(&profile_sync_factory_),
-        load_finished_(false),
-        last_type_(syncer::UNSPECIFIED) {}
-  ~SessionDataTypeControllerTest() override {}
-
-  // FakeSyncClient overrides.
-  PrefService* GetPrefService() override { return &prefs_; }
-
-  void SetUp() override {
-    prefs_.registry()->RegisterBooleanPref(kSavingBrowserHistoryDisabled,
-                                           false);
-
-    local_device_ = std::make_unique<LocalDeviceInfoProviderMock>(
-        "cache_guid", "Wayne Gretzky's Hacking Box", "Chromium 10k",
-        "Chrome 10k", sync_pb::SyncEnums_DeviceType_TYPE_LINUX, "device_id");
-
-    controller_ = std::make_unique<SessionDataTypeController>(
-        base::DoNothing(), this, local_device_.get(),
-        kSavingBrowserHistoryDisabled);
-
-    load_finished_ = false;
-    last_type_ = syncer::UNSPECIFIED;
-    last_error_ = syncer::SyncError();
-  }
-
-  void Start() {
-    controller_->LoadModels(
-        syncer::ConfigureContext(),
-        base::Bind(&SessionDataTypeControllerTest::OnLoadFinished,
-                   base::Unretained(this)));
-  }
-
-  void OnLoadFinished(syncer::ModelType type, const syncer::SyncError& error) {
-    load_finished_ = true;
-    last_type_ = type;
-    last_error_ = error;
-  }
-
-  testing::AssertionResult LoadResult() {
-    if (!load_finished_) {
-      return testing::AssertionFailure() << "OnLoadFinished wasn't called";
-    }
-
-    if (last_error_.IsSet()) {
-      return testing::AssertionFailure()
-             << "OnLoadFinished was called with a SyncError: "
-             << last_error_.ToString();
-    }
-
-    if (last_type_ != syncer::SESSIONS) {
-      return testing::AssertionFailure()
-             << "OnLoadFinished was called with a wrong sync type: "
-             << last_type_;
-    }
-
-    return testing::AssertionSuccess();
-  }
-
-  bool load_finished() const { return load_finished_; }
-  LocalDeviceInfoProviderMock* local_device() { return local_device_.get(); }
-  SessionDataTypeController* controller() { return controller_.get(); }
-
- private:
-  base::MessageLoop message_loop_;
-  TestingPrefServiceSimple prefs_;
-  syncer::SyncApiComponentFactoryMock profile_sync_factory_;
-  std::unique_ptr<LocalDeviceInfoProviderMock> local_device_;
-  std::unique_ptr<SessionDataTypeController> controller_;
-
-  bool load_finished_;
-  syncer::ModelType last_type_;
-  syncer::SyncError last_error_;
-};
-
-TEST_F(SessionDataTypeControllerTest, StartModels) {
-  Start();
-  EXPECT_EQ(syncer::DataTypeController::MODEL_LOADED, controller()->state());
-  EXPECT_TRUE(LoadResult());
-}
-
-}  // namespace
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/session_sync_bridge.cc b/components/sync_sessions/session_sync_bridge.cc
index 00cdfc9..2c240636 100644
--- a/components/sync_sessions/session_sync_bridge.cc
+++ b/components/sync_sessions/session_sync_bridge.cc
@@ -151,14 +151,6 @@
   return syncing_->open_tabs_ui_delegate.get();
 }
 
-syncer::SyncableService* SessionSyncBridge::GetSyncableService() {
-  return nullptr;
-}
-
-syncer::ModelTypeSyncBridge* SessionSyncBridge::GetModelTypeSyncBridge() {
-  return this;
-}
-
 std::unique_ptr<MetadataChangeList>
 SessionSyncBridge::CreateMetadataChangeList() {
   return std::make_unique<syncer::InMemoryMetadataChangeList>();
diff --git a/components/sync_sessions/session_sync_bridge.h b/components/sync_sessions/session_sync_bridge.h
index 8cd390a..de40278f3 100644
--- a/components/sync_sessions/session_sync_bridge.h
+++ b/components/sync_sessions/session_sync_bridge.h
@@ -15,7 +15,6 @@
 #include "components/sync/model/model_error.h"
 #include "components/sync/model/model_type_store.h"
 #include "components/sync/model/model_type_sync_bridge.h"
-#include "components/sync_sessions/abstract_sessions_sync_manager.h"
 #include "components/sync_sessions/favicon_cache.h"
 #include "components/sync_sessions/local_session_event_handler_impl.h"
 #include "components/sync_sessions/open_tabs_ui_delegate_impl.h"
@@ -36,8 +35,7 @@
 // sync server. See
 // https://chromium.googlesource.com/chromium/src/+/lkcr/docs/sync/model_api.md#Implementing-ModelTypeSyncBridge
 // for details.
-class SessionSyncBridge : public AbstractSessionsSyncManager,
-                          public syncer::ModelTypeSyncBridge,
+class SessionSyncBridge : public syncer::ModelTypeSyncBridge,
                           public LocalSessionEventHandlerImpl::Delegate {
  public:
   // Raw pointers must not be null and their pointees must outlive this object.
@@ -47,13 +45,10 @@
       std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor);
   ~SessionSyncBridge() override;
 
-  // AbstractSessionsSyncManager implementation.
-  void ScheduleGarbageCollection() override;
-  FaviconCache* GetFaviconCache() override;
-  SessionsGlobalIdMapper* GetGlobalIdMapper() override;
-  OpenTabsUIDelegate* GetOpenTabsUIDelegate() override;
-  syncer::SyncableService* GetSyncableService() override;
-  syncer::ModelTypeSyncBridge* GetModelTypeSyncBridge() override;
+  void ScheduleGarbageCollection();
+  FaviconCache* GetFaviconCache();
+  SessionsGlobalIdMapper* GetGlobalIdMapper();
+  OpenTabsUIDelegate* GetOpenTabsUIDelegate();
 
   // ModelTypeSyncBridge implementation.
   void OnSyncStarting(
diff --git a/components/sync_sessions/session_sync_service.cc b/components/sync_sessions/session_sync_service.cc
index a272fb7..54e7b8e 100644
--- a/components/sync_sessions/session_sync_service.cc
+++ b/components/sync_sessions/session_sync_service.cc
@@ -8,13 +8,10 @@
 
 #include "base/bind_helpers.h"
 #include "components/sync/base/report_unrecoverable_error.h"
-#include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/model_impl/client_tag_based_model_type_processor.h"
 #include "components/sync_sessions/favicon_cache.h"
-#include "components/sync_sessions/session_data_type_controller.h"
 #include "components/sync_sessions/session_sync_bridge.h"
 #include "components/sync_sessions/session_sync_prefs.h"
-#include "components/sync_sessions/sessions_sync_manager.h"
 #include "components/sync_sessions/sync_sessions_client.h"
 
 namespace sync_sessions {
@@ -24,35 +21,27 @@
     std::unique_ptr<SyncSessionsClient> sessions_client)
     : sessions_client_(std::move(sessions_client)) {
   DCHECK(sessions_client_);
-  if (base::FeatureList::IsEnabled(switches::kSyncUSSSessions)) {
-    sessions_sync_manager_ = std::make_unique<sync_sessions::SessionSyncBridge>(
-        base::BindRepeating(&SessionSyncService::NotifyForeignSessionUpdated,
-                            base::Unretained(this)),
-        sessions_client_.get(),
-        std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
-            syncer::SESSIONS,
-            base::BindRepeating(&syncer::ReportUnrecoverableError, channel)));
-  } else {
-    sessions_sync_manager_ =
-        std::make_unique<sync_sessions::SessionsSyncManager>(
-            base::BindRepeating(
-                &SessionSyncService::NotifyForeignSessionUpdated,
-                base::Unretained(this)),
-            sessions_client_.get());
-  }
+
+  bridge_ = std::make_unique<sync_sessions::SessionSyncBridge>(
+      base::BindRepeating(&SessionSyncService::NotifyForeignSessionUpdated,
+                          base::Unretained(this)),
+      sessions_client_.get(),
+      std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
+          syncer::SESSIONS,
+          base::BindRepeating(&syncer::ReportUnrecoverableError, channel)));
 }
 
 SessionSyncService::~SessionSyncService() {}
 
 syncer::GlobalIdMapper* SessionSyncService::GetGlobalIdMapper() const {
-  return sessions_sync_manager_->GetGlobalIdMapper();
+  return bridge_->GetGlobalIdMapper();
 }
 
 OpenTabsUIDelegate* SessionSyncService::GetOpenTabsUIDelegate() {
   if (!proxy_tabs_running_) {
     return nullptr;
   }
-  return sessions_sync_manager_->GetOpenTabsUIDelegate();
+  return bridge_->GetOpenTabsUIDelegate();
 }
 
 std::unique_ptr<base::CallbackList<void()>::Subscription>
@@ -62,22 +51,16 @@
 }
 
 void SessionSyncService::ScheduleGarbageCollection() {
-  sessions_sync_manager_->ScheduleGarbageCollection();
-}
-
-syncer::SyncableService* SessionSyncService::GetSyncableService() {
-  return sessions_sync_manager_->GetSyncableService();
+  bridge_->ScheduleGarbageCollection();
 }
 
 base::WeakPtr<syncer::ModelTypeControllerDelegate>
 SessionSyncService::GetControllerDelegate() {
-  return sessions_sync_manager_->GetModelTypeSyncBridge()
-      ->change_processor()
-      ->GetControllerDelegate();
+  return bridge_->change_processor()->GetControllerDelegate();
 }
 
 FaviconCache* SessionSyncService::GetFaviconCache() {
-  return sessions_sync_manager_->GetFaviconCache();
+  return bridge_->GetFaviconCache();
 }
 
 void SessionSyncService::ProxyTabsStateChanged(
@@ -95,7 +78,7 @@
 
 OpenTabsUIDelegate*
 SessionSyncService::GetUnderlyingOpenTabsUIDelegateForTest() {
-  return sessions_sync_manager_->GetOpenTabsUIDelegate();
+  return bridge_->GetOpenTabsUIDelegate();
 }
 
 void SessionSyncService::NotifyForeignSessionUpdated() {
diff --git a/components/sync_sessions/session_sync_service.h b/components/sync_sessions/session_sync_service.h
index 34cbab8..2645651 100644
--- a/components/sync_sessions/session_sync_service.h
+++ b/components/sync_sessions/session_sync_service.h
@@ -19,14 +19,13 @@
 namespace syncer {
 class GlobalIdMapper;
 class ModelTypeControllerDelegate;
-class SyncableService;
 }  // namespace syncer
 
 namespace sync_sessions {
 
-class AbstractSessionsSyncManager;
 class FaviconCache;
 class OpenTabsUIDelegate;
+class SessionSyncBridge;
 class SyncSessionsClient;
 
 // KeyedService responsible session sync (aka tab sync), including favicon sync.
@@ -53,9 +52,7 @@
   // Schedules garbage collection of foreign sessions.
   void ScheduleGarbageCollection();
 
-  // For ProfileSyncService to initialize the controller for SESSIONS. Exactly
-  // one of the two below will return non-null (depending on a feature toggle).
-  syncer::SyncableService* GetSyncableService();
+  // For ProfileSyncService to initialize the controller for SESSIONS.
   base::WeakPtr<syncer::ModelTypeControllerDelegate> GetControllerDelegate();
 
   // For ProfileSyncService to initialize the controller for FAVICON_IMAGES and
@@ -80,9 +77,7 @@
 
   bool proxy_tabs_running_ = false;
 
-  // Locally owned SyncableService or ModelTypeSyncBridge implementations.
-  std::unique_ptr<sync_sessions::AbstractSessionsSyncManager>
-      sessions_sync_manager_;
+  std::unique_ptr<SessionSyncBridge> bridge_;
 
   base::CallbackList<void()> foreign_sessions_changed_callback_list_;
 
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc
deleted file mode 100644
index 8320e11..0000000
--- a/components/sync_sessions/sessions_sync_manager.cc
+++ /dev/null
@@ -1,627 +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 "components/sync_sessions/sessions_sync_manager.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "base/bind_helpers.h"
-#include "base/format_macros.h"
-#include "base/logging.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/sequenced_task_runner.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "build/build_config.h"
-#include "components/sync/base/hash_util.h"
-#include "components/sync/model/sync_change_processor.h"
-#include "components/sync/model/sync_error.h"
-#include "components/sync/model/sync_error_factory.h"
-#include "components/sync/model/sync_merge_result.h"
-#include "components/sync/model/time.h"
-#include "components/sync_sessions/local_session_event_router.h"
-#include "components/sync_sessions/session_sync_prefs.h"
-#include "components/sync_sessions/sync_sessions_client.h"
-#include "components/sync_sessions/tab_node_pool.h"
-
-using syncer::DeviceInfo;
-using syncer::SyncChange;
-using syncer::SyncData;
-
-namespace sync_sessions {
-
-namespace {
-
-// Maximum number of favicons to sync.
-// TODO(zea): pull this from the server.
-const int kMaxSyncFavicons = 200;
-
-// Default number of days without activity after which a session is considered
-// stale and becomes a candidate for garbage collection.
-const int kDefaultStaleSessionThresholdDays = 14;  // 2 weeks.
-
-std::string TabNodeIdToTag(const std::string& machine_tag, int tab_node_id) {
-  CHECK_GT(tab_node_id, TabNodePool::kInvalidTabNodeID)
-      << "https://crbug.com/639009";
-  return base::StringPrintf("%s %d", machine_tag.c_str(), tab_node_id);
-}
-
-std::string TagFromSpecifics(const sync_pb::SessionSpecifics& specifics) {
-  if (specifics.has_header()) {
-    return specifics.session_tag();
-  } else if (specifics.has_tab()) {
-    return TabNodeIdToTag(specifics.session_tag(), specifics.tab_node_id());
-  } else {
-    return std::string();
-  }
-}
-
-sync_pb::SessionSpecifics SessionTabToSpecifics(
-    const sessions::SessionTab& session_tab,
-    const std::string& local_tag,
-    int tab_node_id) {
-  sync_pb::SessionSpecifics specifics;
-  SessionTabToSyncData(session_tab).Swap(specifics.mutable_tab());
-  specifics.set_session_tag(local_tag);
-  specifics.set_tab_node_id(tab_node_id);
-  return specifics;
-}
-
-void AppendDeletionsForTabNodes(const std::set<int>& tab_node_ids,
-                                const std::string& machine_tag,
-                                syncer::SyncChangeList* change_output) {
-  for (auto it = tab_node_ids.begin(); it != tab_node_ids.end(); ++it) {
-    change_output->push_back(syncer::SyncChange(
-        FROM_HERE, SyncChange::ACTION_DELETE,
-        SyncData::CreateLocalDelete(TabNodeIdToTag(machine_tag, *it),
-                                    syncer::SESSIONS)));
-  }
-}
-
-class SyncChangeListWriteBatch
-    : public LocalSessionEventHandlerImpl::WriteBatch {
- public:
-  SyncChangeListWriteBatch(
-      const std::string& machine_tag,
-      const std::string& session_name,
-      const std::set<int>& known_tab_node_ids,
-      base::OnceCallback<void(const syncer::SyncChangeList&)> commit_cb)
-      : machine_tag_(machine_tag),
-        session_name_(session_name),
-        known_tab_node_ids_(known_tab_node_ids),
-        commit_cb_(std::move(commit_cb)) {}
-
-  syncer::SyncChangeList* sync_change_list() { return &changes_; }
-
-  void PutWithType(std::unique_ptr<sync_pb::SessionSpecifics> specifics,
-                   SyncChange::SyncChangeType change_type) {
-    sync_pb::EntitySpecifics entity_specifics;
-    specifics->Swap(entity_specifics.mutable_session());
-    changes_.push_back(SyncChange(
-        FROM_HERE, change_type,
-        SyncData::CreateLocalData(TagFromSpecifics(entity_specifics.session()),
-                                  session_name_, entity_specifics)));
-  }
-
-  // WriteBatch implementation.
-  void Delete(int tab_node_id) override {
-    changes_.push_back(syncer::SyncChange(
-        FROM_HERE, SyncChange::ACTION_DELETE,
-        SyncData::CreateLocalDelete(TabNodeIdToTag(machine_tag_, tab_node_id),
-                                    syncer::SESSIONS)));
-  }
-
-  void Put(std::unique_ptr<sync_pb::SessionSpecifics> specifics) override {
-    bool new_entity =
-        specifics->tab_node_id() != TabNodePool::kInvalidTabNodeID &&
-        known_tab_node_ids_.insert(specifics->tab_node_id()).second;
-
-    PutWithType(std::move(specifics), new_entity ? SyncChange::ACTION_ADD
-                                                 : SyncChange::ACTION_UPDATE);
-  }
-
-  void Commit() override { std::move(commit_cb_).Run(changes_); }
-
- private:
-  const std::string machine_tag_;
-  const std::string session_name_;
-  std::set<int> known_tab_node_ids_;
-  base::OnceCallback<void(const syncer::SyncChangeList&)> commit_cb_;
-  syncer::SyncChangeList changes_;
-};
-
-}  // namespace
-
-// |local_device| is owned by ProfileSyncService, its lifetime exceeds
-// lifetime of SessionSyncManager.
-SessionsSyncManager::SessionsSyncManager(
-    const base::RepeatingClosure& notify_foreign_session_updated_cb,
-    sync_sessions::SyncSessionsClient* sessions_client)
-    : notify_foreign_session_updated_cb_(notify_foreign_session_updated_cb),
-      sessions_client_(sessions_client),
-      session_tracker_(sessions_client),
-      favicon_cache_(sessions_client->GetFaviconService(),
-                     sessions_client->GetHistoryService(),
-                     kMaxSyncFavicons),
-      open_tabs_ui_delegate_(
-          sessions_client,
-          &session_tracker_,
-          &favicon_cache_,
-          base::BindRepeating(&SessionsSyncManager::DeleteForeignSessionFromUI,
-                              base::Unretained(this))),
-      local_tab_pool_out_of_sync_(true),
-      stale_session_threshold_days_(kDefaultStaleSessionThresholdDays) {}
-
-SessionsSyncManager::~SessionsSyncManager() {}
-
-// Returns the GUID-based string that should be used for
-// |SessionsSyncManager::current_machine_tag_|.
-static std::string BuildMachineTag(const std::string& cache_guid) {
-  std::string machine_tag = "session_sync";
-  machine_tag.append(cache_guid);
-  return machine_tag;
-}
-
-void SessionsSyncManager::ScheduleGarbageCollection() {
-  base::SequencedTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&SessionsSyncManager::DoGarbageCollection,
-                                base::AsWeakPtr(this)));
-}
-
-syncer::SyncableService* SessionsSyncManager::GetSyncableService() {
-  return this;
-}
-
-syncer::ModelTypeSyncBridge* SessionsSyncManager::GetModelTypeSyncBridge() {
-  return nullptr;
-}
-
-syncer::SyncMergeResult SessionsSyncManager::MergeDataAndStartSyncing(
-    syncer::ModelType type,
-    const syncer::SyncDataList& initial_sync_data,
-    std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
-    std::unique_ptr<syncer::SyncErrorFactory> error_handler) {
-  syncer::SyncMergeResult merge_result(type);
-  DCHECK(session_tracker_.Empty());
-  DCHECK(!local_session_event_handler_);
-
-  error_handler_ = std::move(error_handler);
-  sync_processor_ = std::move(sync_processor);
-
-  // SessionDataTypeController ensures that the local device info
-  // is available before activating this datatype.
-  const DeviceInfo* local_device_info = sessions_client_->GetLocalDeviceInfo();
-  if (!local_device_info) {
-    merge_result.set_error(error_handler_->CreateAndUploadError(
-        FROM_HERE, "Failed to get local device info."));
-    return merge_result;
-  }
-
-  current_session_name_ = local_device_info->client_name();
-
-  // It's possible(via RebuildAssociations) for lost_navigations_recorder_ to
-  // persist between sync being stopped and started. If it did persist, it's
-  // already associated with |sync_processor|, so leave it alone.
-  if (!lost_navigations_recorder_.get()) {
-    lost_navigations_recorder_ =
-        std::make_unique<sync_sessions::LostNavigationsRecorder>();
-    sync_processor_->AddLocalChangeObserver(lost_navigations_recorder_.get());
-  }
-
-  // Make sure we have a machine tag.  We do this now (versus earlier) as it's
-  // a conveniently safe time to assert sync is ready and the cache_guid is
-  // initialized.
-  if (current_machine_tag_.empty()) {
-    InitializeCurrentMachineTag(local_device_info->guid());
-  }
-
-  session_tracker_.InitLocalSession(current_machine_tag_, current_session_name_,
-                                    local_device_info->device_type());
-
-  // TODO(crbug.com/681921): Revisit the somewhat ugly use below of
-  // SyncChangeListWriteBatch. Ideally InitFromSyncModel() could use the
-  // WriteBatch API as well.
-  SyncChangeListWriteBatch batch(current_machine_tag(), current_session_name_,
-                                 /*known_tab_node_ids=*/{},
-                                 /*commit_cb=*/base::DoNothing());
-
-  // First, we iterate over sync data to update our session_tracker_.
-  if (!InitFromSyncModel(initial_sync_data, batch.sync_change_list())) {
-    // The sync db didn't have a header node for us. Create one.
-    auto specifics = std::make_unique<sync_pb::SessionSpecifics>();
-    specifics->set_session_tag(current_machine_tag());
-    sync_pb::SessionHeader* header_s = specifics->mutable_header();
-    header_s->set_client_name(current_session_name_);
-    header_s->set_device_type(local_device_info->device_type());
-    batch.PutWithType(std::move(specifics), SyncChange::ACTION_ADD);
-  }
-
-#if defined(OS_ANDROID)
-  std::string sync_machine_tag(BuildMachineTag(local_device_info->guid()));
-  if (current_machine_tag().compare(sync_machine_tag) != 0)
-    DeleteForeignSessionInternal(sync_machine_tag, batch.sync_change_list());
-#endif
-
-  merge_result.set_error(sync_processor_->ProcessSyncChanges(
-      FROM_HERE, *batch.sync_change_list()));
-
-  local_tab_pool_out_of_sync_ = false;
-
-  // Check if anything has changed on the local client side.
-  local_session_event_handler_ = std::make_unique<LocalSessionEventHandlerImpl>(
-      /*delegate=*/this, sessions_client_, &session_tracker_);
-
-  sessions_client_->GetLocalSessionEventRouter()->StartRoutingTo(
-      local_session_event_handler_.get());
-  return merge_result;
-}
-
-bool SessionsSyncManager::RebuildAssociations() {
-  syncer::SyncDataList data(sync_processor_->GetAllSyncData(syncer::SESSIONS));
-  std::unique_ptr<syncer::SyncErrorFactory> error_handler(
-      std::move(error_handler_));
-  std::unique_ptr<syncer::SyncChangeProcessor> processor(
-      std::move(sync_processor_));
-
-  StopSyncing(syncer::SESSIONS);
-  syncer::SyncMergeResult merge_result = MergeDataAndStartSyncing(
-      syncer::SESSIONS, data, std::move(processor), std::move(error_handler));
-  return !merge_result.error().IsSet();
-}
-
-void SessionsSyncManager::StopSyncing(syncer::ModelType type) {
-  sessions_client_->GetLocalSessionEventRouter()->Stop();
-  local_session_event_handler_.reset();
-  if (sync_processor_.get() && lost_navigations_recorder_.get()) {
-    sync_processor_->RemoveLocalChangeObserver(
-        lost_navigations_recorder_.get());
-    lost_navigations_recorder_.reset();
-  }
-  sync_processor_.reset(nullptr);
-  error_handler_.reset();
-  session_tracker_.Clear();
-  current_machine_tag_.clear();
-  current_session_name_.clear();
-}
-
-syncer::SyncDataList SessionsSyncManager::GetAllSyncData(
-    syncer::ModelType type) const {
-  syncer::SyncDataList list;
-  const SyncedSession* session = session_tracker_.LookupLocalSession();
-  if (!session)
-    return syncer::SyncDataList();
-
-  // First construct the header node.
-  sync_pb::EntitySpecifics header_entity;
-  header_entity.mutable_session()->set_session_tag(current_machine_tag());
-  sync_pb::SessionHeader* header_specifics =
-      header_entity.mutable_session()->mutable_header();
-  header_specifics->MergeFrom(session->ToSessionHeaderProto());
-  syncer::SyncData data = syncer::SyncData::CreateLocalData(
-      current_machine_tag(), current_session_name_, header_entity);
-  list.push_back(data);
-
-  for (const auto& win_iter : session->windows) {
-    for (const auto& tab : win_iter.second->wrapped_window.tabs) {
-      // TODO(zea): replace with with the correct tab node id once there's a
-      // sync specific wrapper for SessionTab. This method is only used in
-      // tests though, so it's fine for now. https://crbug.com/662597
-      int tab_node_id = 0;
-      sync_pb::EntitySpecifics entity;
-      SessionTabToSpecifics(*tab, current_machine_tag(), tab_node_id)
-          .Swap(entity.mutable_session());
-      syncer::SyncData data = syncer::SyncData::CreateLocalData(
-          TabNodeIdToTag(current_machine_tag(), tab_node_id),
-          current_session_name_, entity);
-      list.push_back(data);
-    }
-  }
-  return list;
-}
-
-syncer::SyncError SessionsSyncManager::ProcessSyncChanges(
-    const base::Location& from_here,
-    const syncer::SyncChangeList& change_list) {
-  if (!sync_processor_.get()) {
-    syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
-                            "Models not yet associated.", syncer::SESSIONS);
-    return error;
-  }
-
-  for (auto it = change_list.begin(); it != change_list.end(); ++it) {
-    DCHECK(it->IsValid());
-    DCHECK(it->sync_data().GetSpecifics().has_session());
-    const sync_pb::SessionSpecifics& session =
-        it->sync_data().GetSpecifics().session();
-    const base::Time mtime =
-        syncer::SyncDataRemote(it->sync_data()).GetModifiedTime();
-    switch (it->change_type()) {
-      case syncer::SyncChange::ACTION_DELETE:
-        // Deletions are all or nothing (since we only ever delete entire
-        // sessions). Therefore we don't care if it's a tab node or meta node,
-        // and just ensure we've disassociated.
-        if (current_machine_tag() == session.session_tag()) {
-          // Another client has attempted to delete our local data (possibly by
-          // error or a clock is inaccurate). Just ignore the deletion for now
-          // to avoid any possible ping-pong delete/reassociate sequence, but
-          // remember that this happened as our TabNodePool is inconsistent.
-          local_tab_pool_out_of_sync_ = true;
-          LOG(WARNING) << "Local session data deleted. Ignoring until next "
-                       << "local navigation event.";
-        } else if (session.has_header()) {
-          // Disassociate only when header node is deleted. For tab node
-          // deletions, the header node will be updated and foreign tab will
-          // get deleted.
-          DisassociateForeignSession(session.session_tag());
-        } else if (session.has_tab()) {
-          // The challenge here is that we don't know if this tab deletion is
-          // being processed before or after the parent was updated to no longer
-          // references the tab. Or, even more extreme, the parent has been
-          // deleted as well. Tell the tracker to do what it can. The header's
-          // update will mostly get us into the correct state, the only thing
-          // this deletion needs to accomplish is make sure we never tell sync
-          // to delete this tab later during garbage collection.
-          session_tracker_.DeleteForeignTab(session.session_tag(),
-                                            session.tab_node_id());
-        }
-        break;
-      case syncer::SyncChange::ACTION_ADD:
-      case syncer::SyncChange::ACTION_UPDATE:
-        if (current_machine_tag() == session.session_tag()) {
-          // We should only ever receive a change to our own machine's session
-          // info if encryption was turned on. In that case, the data is still
-          // the same, so we can ignore.
-          LOG(WARNING) << "Dropping modification to local session.";
-          return syncer::SyncError();
-        }
-        UpdateTrackerWithSpecifics(session, mtime, &session_tracker_);
-        // If a favicon or favicon urls are present, load the URLs and visit
-        // times into the in-memory favicon cache.
-        if (session.has_tab()) {
-          favicon_cache_.UpdateMappingsFromForeignTab(session.tab(), mtime);
-        }
-        break;
-      default:
-        NOTREACHED() << "Processing sync changes failed, unknown change type.";
-    }
-  }
-
-  notify_foreign_session_updated_cb_.Run();
-  return syncer::SyncError();
-}
-
-syncer::SyncChange SessionsSyncManager::TombstoneTab(
-    const sync_pb::SessionSpecifics& tab) {
-  if (!tab.has_tab_node_id()) {
-    LOG(WARNING) << "Old sessions node without tab node id; can't tombstone.";
-    return syncer::SyncChange();
-  } else {
-    return syncer::SyncChange(
-        FROM_HERE, SyncChange::ACTION_DELETE,
-        SyncData::CreateLocalDelete(
-            TabNodeIdToTag(current_machine_tag(), tab.tab_node_id()),
-            syncer::SESSIONS));
-  }
-}
-
-bool SessionsSyncManager::InitFromSyncModel(
-    const syncer::SyncDataList& sync_data,
-    syncer::SyncChangeList* new_changes) {
-  bool found_current_header = false;
-  int bad_foreign_hash_count = 0;
-  for (auto it = sync_data.begin(); it != sync_data.end(); ++it) {
-    const syncer::SyncData& data = *it;
-    DCHECK(data.GetSpecifics().has_session());
-    syncer::SyncDataRemote remote(data);
-    const sync_pb::SessionSpecifics& specifics = data.GetSpecifics().session();
-    if (specifics.session_tag().empty() ||
-        (specifics.has_tab() &&
-         (!specifics.has_tab_node_id() || !specifics.tab().has_tab_id()))) {
-      syncer::SyncChange tombstone(TombstoneTab(specifics));
-      if (tombstone.IsValid())
-        new_changes->push_back(tombstone);
-    } else if (specifics.session_tag() != current_machine_tag()) {
-      if (TagHashFromSpecifics(specifics) == remote.GetClientTagHash()) {
-        UpdateTrackerWithSpecifics(specifics, remote.GetModifiedTime(),
-                                   &session_tracker_);
-        // If a favicon or favicon urls are present, load the URLs and visit
-        // times into the in-memory favicon cache.
-        if (specifics.has_tab()) {
-          favicon_cache_.UpdateMappingsFromForeignTab(specifics.tab(),
-                                                      remote.GetModifiedTime());
-        }
-      } else {
-        // In the past, like years ago, we believe that some session data was
-        // created with bad tag hashes. This causes any change this client makes
-        // to that foreign data (like deletion through garbage collection) to
-        // trigger a data type error because the tag looking mechanism fails. So
-        // look for these and delete via remote SyncData, which uses a server id
-        // lookup mechanism instead, see https://crbug.com/604657.
-        bad_foreign_hash_count++;
-        new_changes->push_back(
-            syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE, remote));
-      }
-    } else {
-      // This is previously stored local session information.
-      if (specifics.has_header() && !found_current_header) {
-        // This is our previous header node, reuse it.
-        found_current_header = true;
-
-        UpdateTrackerWithSpecifics(specifics, remote.GetModifiedTime(),
-                                   &session_tracker_);
-        DVLOG(1) << "Loaded local header.";
-      } else {
-        if (specifics.has_header() || !specifics.has_tab()) {
-          LOG(WARNING) << "Found more than one session header node with local "
-                       << "tag.";
-          syncer::SyncChange tombstone(TombstoneTab(specifics));
-          if (tombstone.IsValid())
-            new_changes->push_back(tombstone);
-        } else if (specifics.tab().tab_id() <= 0) {
-          LOG(WARNING) << "Found tab node with invalid tab id.";
-          syncer::SyncChange tombstone(TombstoneTab(specifics));
-          if (tombstone.IsValid())
-            new_changes->push_back(tombstone);
-        } else {
-          // This is a valid old tab node, add it to the tracker and associate
-          // it (using the new tab id).
-          DVLOG(1) << "Associating local tab " << specifics.tab().tab_id()
-                   << " with node " << specifics.tab_node_id();
-
-          session_tracker_.ReassociateLocalTab(
-              specifics.tab_node_id(),
-              SessionID::FromSerializedValue(specifics.tab().tab_id()));
-          UpdateTrackerWithSpecifics(specifics, remote.GetModifiedTime(),
-                                     &session_tracker_);
-        }
-      }
-    }
-  }
-
-  // Cleanup all foreign sessions, since orphaned tabs may have been added after
-  // the header.
-  for (const auto* session :
-       session_tracker_.LookupAllForeignSessions(SyncedSessionTracker::RAW)) {
-    session_tracker_.CleanupSession(session->session_tag);
-  }
-
-  UMA_HISTOGRAM_COUNTS_100("Sync.SessionsBadForeignHashOnMergeCount",
-                           bad_foreign_hash_count);
-
-  return found_current_header;
-}
-
-void SessionsSyncManager::InitializeCurrentMachineTag(
-    const std::string& cache_guid) {
-  DCHECK(current_machine_tag_.empty());
-  std::string persisted_guid;
-  persisted_guid =
-      sessions_client_->GetSessionSyncPrefs()->GetSyncSessionsGUID();
-  if (!persisted_guid.empty()) {
-    current_machine_tag_ = persisted_guid;
-    DVLOG(1) << "Restoring persisted session sync guid: " << persisted_guid;
-  } else {
-    DCHECK(!cache_guid.empty());
-    current_machine_tag_ = BuildMachineTag(cache_guid);
-    DVLOG(1) << "Creating session sync guid: " << current_machine_tag_;
-    sessions_client_->GetSessionSyncPrefs()->SetSyncSessionsGUID(
-        current_machine_tag_);
-  }
-}
-
-void SessionsSyncManager::DeleteForeignSessionInternal(
-    const std::string& tag,
-    syncer::SyncChangeList* change_output) {
-  if (tag == current_machine_tag()) {
-    LOG(ERROR) << "Attempting to delete local session. This is not currently "
-               << "supported.";
-    return;
-  }
-
-  const std::set<int> tab_node_ids_to_delete =
-      session_tracker_.LookupTabNodeIds(tag);
-  if (DisassociateForeignSession(tag)) {
-    // Only tell sync to delete the header if there was one.
-    change_output->push_back(
-        syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE,
-                           SyncData::CreateLocalDelete(tag, syncer::SESSIONS)));
-  }
-  AppendDeletionsForTabNodes(tab_node_ids_to_delete, tag, change_output);
-
-  notify_foreign_session_updated_cb_.Run();
-}
-
-void SessionsSyncManager::DeleteForeignSessionFromUI(const std::string& tag) {
-  syncer::SyncChangeList changes;
-  DeleteForeignSessionInternal(tag, &changes);
-  sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
-}
-
-bool SessionsSyncManager::DisassociateForeignSession(
-    const std::string& foreign_session_tag) {
-  DCHECK_NE(foreign_session_tag, current_machine_tag());
-  DVLOG(1) << "Disassociating session " << foreign_session_tag;
-  return session_tracker_.DeleteForeignSession(foreign_session_tag);
-}
-
-std::unique_ptr<LocalSessionEventHandlerImpl::WriteBatch>
-SessionsSyncManager::CreateLocalSessionWriteBatch() {
-  return std::make_unique<SyncChangeListWriteBatch>(
-      current_machine_tag(), current_session_name_,
-      /*known_tab_node_ids=*/
-      session_tracker_.LookupTabNodeIds(current_machine_tag()),
-      /*commit_cb=*/
-      base::BindOnce(&SessionsSyncManager::ProcessLocalSessionSyncChanges,
-                     base::AsWeakPtr(this)));
-}
-
-void SessionsSyncManager::TrackLocalNavigationId(base::Time timestamp,
-                                                 int unique_id) {
-  global_id_mapper_.TrackNavigationId(timestamp, unique_id);
-}
-
-void SessionsSyncManager::OnPageFaviconUpdated(const GURL& page_url) {
-  favicon_cache_.OnPageFaviconUpdated(page_url, base::Time::Now());
-}
-
-void SessionsSyncManager::OnFaviconVisited(const GURL& page_url,
-                                           const GURL& favicon_url) {
-  favicon_cache_.OnFaviconVisited(page_url, favicon_url);
-}
-
-FaviconCache* SessionsSyncManager::GetFaviconCache() {
-  return &favicon_cache_;
-}
-
-SessionsGlobalIdMapper* SessionsSyncManager::GetGlobalIdMapper() {
-  return &global_id_mapper_;
-}
-
-OpenTabsUIDelegate* SessionsSyncManager::GetOpenTabsUIDelegate() {
-  return &open_tabs_ui_delegate_;
-}
-
-void SessionsSyncManager::DoGarbageCollection() {
-  // Iterate through all the sessions and delete any with age older than
-  // |stale_session_threshold_days_|.
-  syncer::SyncChangeList changes;
-  for (const auto* session :
-       session_tracker_.LookupAllForeignSessions(SyncedSessionTracker::RAW)) {
-    int session_age_in_days =
-        (base::Time::Now() - session->modified_time).InDays();
-    if (session_age_in_days > stale_session_threshold_days_) {
-      std::string session_tag = session->session_tag;
-      DVLOG(1) << "Found stale session " << session_tag << " with age "
-               << session_age_in_days << ", deleting.";
-      DeleteForeignSessionInternal(session_tag, &changes);
-    }
-  }
-
-  if (!changes.empty())
-    sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// static
-std::string SessionsSyncManager::TagHashFromSpecifics(
-    const sync_pb::SessionSpecifics& specifics) {
-  return syncer::GenerateSyncableHash(syncer::SESSIONS,
-                                      TagFromSpecifics(specifics));
-}
-
-void SessionsSyncManager::ProcessLocalSessionSyncChanges(
-    const syncer::SyncChangeList& change_list) {
-  if (local_tab_pool_out_of_sync_) {
-    // If our tab pool is corrupt, pay the price of a full re-association to
-    // fix things up.  This takes care of the new tab modification as well.
-    bool rebuild_association_succeeded = RebuildAssociations();
-    DCHECK(!rebuild_association_succeeded || !local_tab_pool_out_of_sync_);
-    return;
-  }
-
-  sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/sessions_sync_manager.h b/components/sync_sessions/sessions_sync_manager.h
deleted file mode 100644
index 1c3e636..0000000
--- a/components/sync_sessions/sessions_sync_manager.h
+++ /dev/null
@@ -1,213 +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 COMPONENTS_SYNC_SESSIONS_SESSIONS_SYNC_MANAGER_H_
-#define COMPONENTS_SYNC_SESSIONS_SESSIONS_SYNC_MANAGER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "components/sessions/core/session_id.h"
-#include "components/sessions/core/session_types.h"
-#include "components/sync/device_info/device_info.h"
-#include "components/sync/model/syncable_service.h"
-#include "components/sync_sessions/abstract_sessions_sync_manager.h"
-#include "components/sync_sessions/favicon_cache.h"
-#include "components/sync_sessions/local_session_event_handler_impl.h"
-#include "components/sync_sessions/lost_navigations_recorder.h"
-#include "components/sync_sessions/open_tabs_ui_delegate_impl.h"
-#include "components/sync_sessions/sessions_global_id_mapper.h"
-#include "components/sync_sessions/synced_session.h"
-#include "components/sync_sessions/synced_session_tracker.h"
-
-namespace syncer {
-class SyncErrorFactory;
-}  // namespace syncer
-
-namespace sync_pb {
-class SessionSpecifics;
-class SessionTab;
-}  // namespace sync_pb
-
-namespace extensions {
-class ExtensionSessionsTest;
-}  // namespace extensions
-
-namespace sync_sessions {
-
-// Contains all logic for associating the Chrome sessions model and
-// the sync sessions model.
-class SessionsSyncManager : public AbstractSessionsSyncManager,
-                            public syncer::SyncableService,
-                            public LocalSessionEventHandlerImpl::Delegate {
- public:
-  SessionsSyncManager(
-      const base::RepeatingClosure& notify_foreign_session_updated_cb,
-      SyncSessionsClient* sessions_client);
-  ~SessionsSyncManager() override;
-
-  // AbstractSessionsSyncManager implementation.
-  void ScheduleGarbageCollection() override;
-  FaviconCache* GetFaviconCache() override;
-  SessionsGlobalIdMapper* GetGlobalIdMapper() override;
-  OpenTabsUIDelegate* GetOpenTabsUIDelegate() override;
-  syncer::SyncableService* GetSyncableService() override;
-  syncer::ModelTypeSyncBridge* GetModelTypeSyncBridge() override;
-
-  // syncer::SyncableService implementation.
-  syncer::SyncMergeResult MergeDataAndStartSyncing(
-      syncer::ModelType type,
-      const syncer::SyncDataList& initial_sync_data,
-      std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
-      std::unique_ptr<syncer::SyncErrorFactory> error_handler) override;
-  void StopSyncing(syncer::ModelType type) override;
-  syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override;
-  syncer::SyncError ProcessSyncChanges(
-      const base::Location& from_here,
-      const syncer::SyncChangeList& change_list) override;
-
-  // LocalSessionEventHandlerImpl::Delegate implementation.
-  std::unique_ptr<LocalSessionEventHandlerImpl::WriteBatch>
-  CreateLocalSessionWriteBatch() override;
-  void TrackLocalNavigationId(base::Time timestamp, int unique_id) override;
-  void OnPageFaviconUpdated(const GURL& page_url) override;
-  void OnFaviconVisited(const GURL& page_url, const GURL& favicon_url) override;
-
-  // Returns the tag used to uniquely identify this machine's session in the
-  // sync model.
-  const std::string& current_machine_tag() const {
-    DCHECK(!current_machine_tag_.empty());
-    return current_machine_tag_;
-  }
-
-  const std::string GetCurrentSessionNameForTest() const {
-    return current_session_name_;
-  }
-
-  // Triggers garbage collection of stale sessions (as defined by
-  // |stale_session_threshold_days_|). This is called every time we see new
-  // sessions data downloaded (sync cycles complete).
-  void DoGarbageCollection();
-
- private:
-  friend class extensions::ExtensionSessionsTest;
-  friend class SessionsSyncManagerTest;
-  FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, BlockedNavigations);
-  FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, DeleteForeignSession);
-  FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest,
-                           ProcessForeignDeleteTabsWithShadowing);
-  FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest,
-                           ProcessForeignDeleteTabsWithReusedNodeIds);
-  FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, MergeDeletesBadHash);
-  FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest,
-                           MergeLocalSessionExistingTabs);
-  FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest,
-                           AssociateWindowsDontReloadTabs);
-  FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, SwappedOutOnRestore);
-  FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest,
-                           ProcessRemoteDeleteOfLocalSession);
-
-  void InitializeCurrentMachineTag(const std::string& cache_guid);
-
-  // Returns true if |sync_data| contained a header node for the current
-  // machine, false otherwise. |new_changes| is a link to the SyncChange
-  // pipeline that exists in the caller's context. This function will append
-  // necessary changes for processing later.
-  bool InitFromSyncModel(const syncer::SyncDataList& sync_data,
-                         syncer::SyncChangeList* new_changes);
-
-  // Helper to construct a deletion SyncChange for a *tab node*.
-  // Caller should check IsValid() on the returned change, as it's possible
-  // this node could not be deleted.
-  syncer::SyncChange TombstoneTab(const sync_pb::SessionSpecifics& tab);
-
-  // Removes a foreign session from our internal bookkeeping.
-  // Returns true if the session was found and deleted, false if no data was
-  // found for that session.  This will *NOT* trigger sync deletions. See
-  // DeleteForeignSession below.
-  bool DisassociateForeignSession(const std::string& foreign_session_tag);
-
-  // Delete a foreign session and all its sync data.
-  // |change_output| *must* be provided as a link to the SyncChange pipeline
-  // that exists in the caller's context. This function will append necessary
-  // changes for processing later.
-  void DeleteForeignSessionInternal(const std::string& tag,
-                                    syncer::SyncChangeList* change_output);
-
-  // Same as above but it also notifies the processor.
-  void DeleteForeignSessionFromUI(const std::string& tag);
-
-  // Stops and re-starts syncing to rebuild association mappings. Returns true
-  // when re-starting succeeds.
-  // See |local_tab_pool_out_of_sync_|.
-  bool RebuildAssociations();
-
-  // Calculates the tag hash from a specifics object. Calculating the hash is
-  // something we typically want to avoid doing in the model type like this.
-  // However, the only place that understands how to generate a tag from the
-  // specifics is the model type, ie us. We need to generate the tag because it
-  // is not passed over the wire for remote data. The use case this function was
-  // created for is detecting bad tag hashes from remote data, see
-  // https://crbug.com/604657.
-  static std::string TagHashFromSpecifics(
-      const sync_pb::SessionSpecifics& specifics);
-
-  void ProcessLocalSessionSyncChanges(
-      const syncer::SyncChangeList& change_list);
-
-  const base::RepeatingClosure notify_foreign_session_updated_cb_;
-
-  // The client of this sync sessions datatype.
-  SyncSessionsClient* const sessions_client_;
-
-  SyncedSessionTracker session_tracker_;
-  SessionsGlobalIdMapper global_id_mapper_;
-  FaviconCache favicon_cache_;
-  OpenTabsUIDelegateImpl open_tabs_ui_delegate_;
-
-  // Instantiated when sync is enabled.
-  std::unique_ptr<LocalSessionEventHandlerImpl> local_session_event_handler_;
-
-  // Tracks whether our local representation of which sync nodes map to what
-  // tabs (belonging to the current local session) is inconsistent.  This can
-  // happen if a foreign client deems our session as "stale" and decides to
-  // delete it. Rather than respond by bullishly re-creating our nodes
-  // immediately, which could lead to ping-pong sequences, we give the benefit
-  // of the doubt and hold off until another local navigation occurs, which
-  // proves that we are still relevant.
-  bool local_tab_pool_out_of_sync_;
-
-  std::unique_ptr<syncer::SyncErrorFactory> error_handler_;
-  std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_;
-
-  // Unique client tag.
-  std::string current_machine_tag_;
-
-  // User-visible machine name to populate header.
-  std::string current_session_name_;
-
-  // Number of days without activity after which we consider a session to be
-  // stale and a candidate for garbage collection.
-  int stale_session_threshold_days_;
-
-  std::unique_ptr<sync_sessions::LostNavigationsRecorder>
-      lost_navigations_recorder_;
-
-  DISALLOW_COPY_AND_ASSIGN(SessionsSyncManager);
-};
-
-}  // namespace sync_sessions
-
-#endif  // COMPONENTS_SYNC_SESSIONS_SESSIONS_SYNC_MANAGER_H_
diff --git a/components/sync_sessions/sessions_sync_manager_unittest.cc b/components/sync_sessions/sessions_sync_manager_unittest.cc
deleted file mode 100644
index 1844e9fd..0000000
--- a/components/sync_sessions/sessions_sync_manager_unittest.cc
+++ /dev/null
@@ -1,1930 +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 "components/sync_sessions/sessions_sync_manager.h"
-
-#include <stdint.h>
-
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/test/mock_callback.h"
-#include "build/build_config.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/sync/model/sync_change_processor.h"
-#include "components/sync/model/sync_error_factory_mock.h"
-#include "components/sync_sessions/mock_sync_sessions_client.h"
-#include "components/sync_sessions/session_sync_prefs.h"
-#include "components/sync_sessions/session_sync_test_helper.h"
-#include "components/sync_sessions/sync_sessions_client.h"
-#include "components/sync_sessions/test_synced_window_delegates_getter.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using syncer::DeviceInfo;
-using syncer::SyncChange;
-using syncer::SyncChangeList;
-using syncer::SyncData;
-using syncer::SyncDataList;
-using syncer::SyncDataLocal;
-using syncer::SyncError;
-using testing::ElementsAre;
-using testing::Eq;
-using testing::IsNull;
-
-namespace sync_sessions {
-
-namespace {
-
-const char kCacheGuid[] = "cache_guid";
-const char kFoo1[] = "http://foo1/";
-const char kFoo2[] = "http://foo2/";
-const char kBar1[] = "http://bar1/";
-const char kBar2[] = "http://bar2/";
-const char kBaz1[] = "http://baz1/";
-const char kTag1[] = "tag1";
-const char kTag2[] = "tag2";
-
-std::vector<SessionID> SessionIDs(const std::vector<SessionID::id_type>& ids) {
-  std::vector<SessionID> result;
-  for (SessionID::id_type id : ids) {
-    result.push_back(SessionID::FromSerializedValue(id));
-  }
-  return result;
-}
-
-std::string TabNodeIdToTag(const std::string& machine_tag, int tab_node_id) {
-  return base::StringPrintf("%s %d", machine_tag.c_str(), tab_node_id);
-}
-
-size_t CountIfTagMatches(const SyncChangeList& changes,
-                         const std::string& tag) {
-  return std::count_if(
-      changes.begin(), changes.end(), [&tag](const SyncChange& change) {
-        return change.sync_data().GetSpecifics().session().session_tag() == tag;
-      });
-}
-
-size_t CountIfTagMatches(const std::vector<const SyncedSession*>& sessions,
-                         const std::string& tag) {
-  return std::count_if(sessions.begin(), sessions.end(),
-                       [&tag](const SyncedSession* session) {
-                         return session->session_tag == tag;
-                       });
-}
-
-testing::AssertionResult AllOfChangesAreType(
-    const SyncChangeList& changes,
-    const SyncChange::SyncChangeType type) {
-  auto invalid_change = std::find_if(changes.begin(), changes.end(),
-                                     [&type](const SyncChange& change) {
-                                       return change.change_type() != type;
-                                     });
-  if (invalid_change != changes.end()) {
-    return testing::AssertionFailure() << invalid_change->ToString()
-                                       << " doesn't match "
-                                       << SyncChange::ChangeTypeToString(type);
-  }
-  return testing::AssertionSuccess();
-}
-
-testing::AssertionResult ChangeTypeMatches(
-    const SyncChangeList& changes,
-    const std::vector<SyncChange::SyncChangeType>& types) {
-  auto types_iter = types.begin();
-  if (changes.size() != types.size() ||
-      std::any_of(changes.begin(), changes.end(),
-                  [&types_iter](const SyncChange& change) {
-                    SCOPED_TRACE(change.ToString());
-                    return change.change_type() != *types_iter++;
-                  })) {
-    std::string type_string;
-    std::for_each(types.begin(), types.end(),
-                  [&type_string](const SyncChange::SyncChangeType& type) {
-                    (type_string) += SyncChange::ChangeTypeToString(type) + " ";
-                  });
-    std::string change_string;
-    std::for_each(changes.begin(), changes.end(),
-                  [&change_string](const SyncChange& change) {
-                    change_string += change.ToString();
-                  });
-    return testing::AssertionFailure()
-           << "Change type mismatch: " << type_string << " vs "
-           << change_string;
-  }
-  return testing::AssertionSuccess();
-}
-
-class TestSyncChangeProcessor : public syncer::SyncChangeProcessor {
- public:
-  explicit TestSyncChangeProcessor(SyncChangeList* output) : output_(output) {}
-  SyncError ProcessSyncChanges(const base::Location& from_here,
-                               const SyncChangeList& change_list) override {
-    if (error_.IsSet()) {
-      SyncError error = error_;
-      error_ = SyncError();
-      return error;
-    }
-
-    if (output_)
-      output_->insert(output_->end(), change_list.begin(), change_list.end());
-    NotifyLocalChangeObservers();
-
-    return SyncError();
-  }
-
-  SyncDataList GetAllSyncData(syncer::ModelType type) const override {
-    return SyncDataList();
-  }
-
-  void AddLocalChangeObserver(syncer::LocalChangeObserver* observer) override {
-    local_change_observers_.AddObserver(observer);
-  }
-  void RemoveLocalChangeObserver(
-      syncer::LocalChangeObserver* observer) override {
-    local_change_observers_.RemoveObserver(observer);
-  }
-
-  void NotifyLocalChangeObservers() {
-    const SyncChange empty_change;
-    for (syncer::LocalChangeObserver& observer : local_change_observers_)
-      observer.OnLocalChange(nullptr, empty_change);
-  }
-
-  void FailProcessSyncChangesWith(const SyncError& error) { error_ = error; }
-
- private:
-  SyncError error_;
-  SyncChangeList* output_;
-  base::ObserverList<syncer::LocalChangeObserver>::Unchecked
-      local_change_observers_;
-};
-
-}  // namespace
-
-class SessionsSyncManagerTest : public testing::Test {
- protected:
-  const SessionID kWindowId1 = SessionID::FromSerializedValue(1);
-  const SessionID kWindowId2 = SessionID::FromSerializedValue(2);
-  const std::vector<SessionID> kTabIds1 = SessionIDs({5, 10, 13, 17});
-  const std::vector<SessionID> kTabIds2 = SessionIDs({7, 15, 18, 20});
-
-  SessionsSyncManagerTest()
-      : local_device_info_(kCacheGuid,
-                           "Wayne Gretzky's Hacking Box",
-                           "Chromium 10k",
-                           "Chrome 10k",
-                           sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
-                           "device_id"),
-        session_sync_prefs_(&pref_service_) {}
-
-  void SetUp() override {
-    SessionSyncPrefs::RegisterProfilePrefs(pref_service_.registry());
-
-    ON_CALL(mock_sync_sessions_client_, GetSessionSyncPrefs())
-        .WillByDefault(testing::Return(&session_sync_prefs_));
-    ON_CALL(mock_sync_sessions_client_, GetLocalDeviceInfo())
-        .WillByDefault(testing::Return(&local_device_info_));
-    ON_CALL(mock_sync_sessions_client_, GetSyncedWindowDelegatesGetter())
-        .WillByDefault(testing::Return(&window_getter_));
-    ON_CALL(mock_sync_sessions_client_, GetLocalSessionEventRouter())
-        .WillByDefault(testing::Return(window_getter_.router()));
-
-    manager_ = std::make_unique<SessionsSyncManager>(
-        mock_foreign_session_updated_cb_.Get(), &mock_sync_sessions_client_);
-  }
-
-  void TearDown() override {
-    test_processor_ = nullptr;
-    helper()->Reset();
-    manager_.reset();
-  }
-
-  const DeviceInfo* GetLocalDeviceInfo() { return &local_device_info_; }
-
-  SessionsSyncManager* manager() { return manager_.get(); }
-  SessionSyncTestHelper* helper() { return &helper_; }
-  MockSyncSessionsClient* mock_sync_sessions_client() {
-    return &mock_sync_sessions_client_;
-  }
-
-  base::MockCallback<base::RepeatingClosure>*
-  mock_foreign_session_updated_cb() {
-    return &mock_foreign_session_updated_cb_;
-  }
-
-  void InitWithSyncDataTakeOutput(const SyncDataList& initial_data,
-                                  SyncChangeList* output) {
-    test_processor_ = new TestSyncChangeProcessor(output);
-    syncer::SyncMergeResult result = manager_->MergeDataAndStartSyncing(
-        syncer::SESSIONS, initial_data,
-        std::unique_ptr<syncer::SyncChangeProcessor>(test_processor_),
-        std::unique_ptr<syncer::SyncErrorFactory>(
-            new syncer::SyncErrorFactoryMock()));
-    EXPECT_FALSE(result.error().IsSet());
-  }
-
-  void InitWithNoSyncData() {
-    InitWithSyncDataTakeOutput(SyncDataList(), nullptr);
-  }
-
-  void TriggerProcessSyncChangesError() {
-    test_processor_->FailProcessSyncChangesWith(SyncError(
-        FROM_HERE, SyncError::DATATYPE_ERROR, "Error", syncer::SESSIONS));
-  }
-
-  void VerifyLocalHeaderChange(const SyncChange& change,
-                               int num_windows,
-                               int num_tabs) {
-    SCOPED_TRACE(change.ToString());
-    SyncDataLocal data(change.sync_data());
-    EXPECT_EQ(manager()->current_machine_tag(), data.GetTag());
-    ASSERT_TRUE(data.GetSpecifics().session().has_header());
-    EXPECT_FALSE(data.GetSpecifics().session().has_tab());
-    EXPECT_TRUE(data.GetSpecifics().session().header().has_device_type());
-    EXPECT_EQ(GetLocalDeviceInfo()->client_name(),
-              data.GetSpecifics().session().header().client_name());
-    EXPECT_EQ(num_windows,
-              data.GetSpecifics().session().header().window_size());
-    int tab_count = 0;
-    for (auto& window : data.GetSpecifics().session().header().window()) {
-      tab_count += window.tab_size();
-    }
-    EXPECT_EQ(num_tabs, tab_count);
-  }
-
-  void VerifyLocalTabChange(const SyncChange& change,
-                            int num_navigations,
-                            std::string final_url) {
-    SCOPED_TRACE(change.ToString());
-    SyncDataLocal data(change.sync_data());
-    EXPECT_TRUE(base::StartsWith(data.GetTag(),
-                                 manager()->current_machine_tag(),
-                                 base::CompareCase::SENSITIVE));
-    EXPECT_FALSE(data.GetSpecifics().session().has_header());
-    ASSERT_TRUE(data.GetSpecifics().session().has_tab());
-    ASSERT_EQ(num_navigations,
-              data.GetSpecifics().session().tab().navigation_size());
-    EXPECT_EQ(final_url, data.GetSpecifics()
-                             .session()
-                             .tab()
-                             .navigation(num_navigations - 1)
-                             .virtual_url());
-  }
-
-  SyncChangeList* FilterOutLocalHeaderChanges(SyncChangeList* list) {
-    auto it = list->begin();
-    bool found = false;
-    while (it != list->end()) {
-      if (it->sync_data().IsLocal() &&
-          SyncDataLocal(it->sync_data()).GetTag() ==
-              manager_->current_machine_tag()) {
-        EXPECT_TRUE(SyncChange::ACTION_ADD == it->change_type() ||
-                    SyncChange::ACTION_UPDATE == it->change_type());
-        it = list->erase(it);
-        found = true;
-      } else {
-        ++it;
-      }
-    }
-    EXPECT_TRUE(found);
-    return list;
-  }
-
-  SyncChange MakeRemoteChange(const sync_pb::SessionSpecifics& specifics,
-                              SyncChange::SyncChangeType type) const {
-    return SyncChange(FROM_HERE, type, CreateRemoteData(specifics));
-  }
-
-  void AddTabsToChangeList(const std::vector<sync_pb::SessionSpecifics>& batch,
-                           SyncChange::SyncChangeType type,
-                           SyncChangeList* change_list) const {
-    for (const auto& specifics : batch) {
-      change_list->push_back(
-          SyncChange(FROM_HERE, type, CreateRemoteData(specifics)));
-    }
-  }
-
-  void AddToSyncDataList(const sync_pb::SessionSpecifics& specifics,
-                         SyncDataList* list,
-                         base::Time mtime) const {
-    list->push_back(CreateRemoteData(specifics, mtime));
-  }
-
-  void AddTabsToSyncDataList(const std::vector<sync_pb::SessionSpecifics>& tabs,
-                             SyncDataList* list) const {
-    for (size_t i = 0; i < tabs.size(); ++i) {
-      AddToSyncDataList(tabs[i], list, base::Time::FromInternalValue(i + 1));
-    }
-  }
-
-  SyncData CreateRemoteData(const sync_pb::SessionSpecifics& specifics,
-                            base::Time mtime = base::Time()) const {
-    sync_pb::EntitySpecifics entity;
-    entity.mutable_session()->CopyFrom(specifics);
-    return CreateRemoteData(entity, mtime);
-  }
-
-  SyncData CreateRemoteData(const sync_pb::EntitySpecifics& entity,
-                            base::Time mtime = base::Time()) const {
-    // The server ID is never relevant to these tests, so just use 1.
-    return SyncData::CreateRemoteData(
-        1, entity, mtime,
-        SessionsSyncManager::TagHashFromSpecifics(entity.session()));
-  }
-
-  syncer::SyncDataList GetDataFromChanges(
-      const syncer::SyncChangeList& changes) {
-    syncer::SyncDataList data_list;
-    for (auto& change : changes) {
-      syncer::SyncDataLocal change_data(change.sync_data());
-      bool found = false;
-      for (auto&& data : data_list) {
-        syncer::SyncDataLocal local_data(data);
-        if (local_data.GetTag() == change_data.GetTag()) {
-          data = change.sync_data();
-          found = true;
-          break;
-        }
-      }
-      if (!found)
-        data_list.push_back(change_data);
-    }
-    return data_list;
-  }
-
-  syncer::SyncDataList ConvertToRemote(const syncer::SyncDataList& in) {
-    syncer::SyncDataList out;
-    for (auto& data : in) {
-      out.push_back(CreateRemoteData(data.GetSpecifics()));
-    }
-    return out;
-  }
-
-  void ResetWindows() { return window_getter_.ResetWindows(); }
-
-  TestSyncedWindowDelegate* AddWindow(
-      sync_pb::SessionWindow_BrowserType type =
-          sync_pb::SessionWindow_BrowserType_TYPE_TABBED) {
-    return window_getter_.AddWindow(type);
-  }
-
-  TestSyncedTabDelegate* AddTab(SessionID window_id, const std::string& url) {
-    TestSyncedTabDelegate* tab = window_getter_.AddTab(window_id);
-    tab->Navigate(url);
-    return tab;
-  }
-
- private:
-  const syncer::DeviceInfo local_device_info_;
-  TestingPrefServiceSimple pref_service_;
-  SessionSyncPrefs session_sync_prefs_;
-  testing::NiceMock<MockSyncSessionsClient> mock_sync_sessions_client_;
-  testing::NiceMock<base::MockCallback<base::RepeatingClosure>>
-      mock_foreign_session_updated_cb_;
-  std::unique_ptr<SessionsSyncManager> manager_;
-  SessionSyncTestHelper helper_;
-  TestSyncChangeProcessor* test_processor_ = nullptr;
-  TestSyncedWindowDelegatesGetter window_getter_;
-};
-
-// Tests that the local session header objects is created properly in
-// presence of no other session activity, once and only once.
-TEST_F(SessionsSyncManagerTest, MergeLocalSessionNoTabs) {
-  // Add a single window with no tabs.
-  AddWindow();
-
-  SyncChangeList out;
-  InitWithSyncDataTakeOutput(SyncDataList(), &out);
-  EXPECT_FALSE(manager()->current_machine_tag().empty());
-
-  // Header creation + update.
-  ASSERT_TRUE(ChangeTypeMatches(
-      out, {SyncChange::ACTION_ADD, SyncChange::ACTION_UPDATE}));
-  EXPECT_EQ(out.size(),
-            CountIfTagMatches(out, manager()->current_machine_tag()));
-  VerifyLocalHeaderChange(out[0], 0, 0);
-  VerifyLocalHeaderChange(out[1], 0, 0);
-
-  // Now take that header node and feed it in as input.
-  SyncData d = CreateRemoteData(out[1].sync_data().GetSpecifics());
-  SyncDataList in = {d};
-  out.clear();
-  manager()->StopSyncing(syncer::SESSIONS);
-  InitWithSyncDataTakeOutput(in, &out);
-
-  ASSERT_TRUE(ChangeTypeMatches(out, {SyncChange::ACTION_UPDATE}));
-  EXPECT_TRUE(out[0].sync_data().GetSpecifics().session().has_header());
-}
-
-// Ensure that tabbed windows from a previous session are preserved if no
-// windows are present on startup.
-TEST_F(SessionsSyncManagerTest, PreserveTabbedDataNoWindows) {
-  syncer::SyncDataList in;
-  syncer::SyncChangeList out;
-
-  // Set up one tab and start sync with it.
-  TestSyncedTabDelegate* tab = AddTab(AddWindow()->GetSessionId(), kFoo1);
-  tab->Navigate(kFoo2);
-  InitWithSyncDataTakeOutput(in, &out);
-
-  // There should be two entities, a header and a tab.
-  in = GetDataFromChanges(out);
-  out.clear();
-  ASSERT_EQ(2U, in.size());
-
-  // Resync, using the previous sync data, but with no windows open now.
-  manager()->StopSyncing(syncer::SESSIONS);
-  ResetWindows();
-  InitWithSyncDataTakeOutput(ConvertToRemote(in), &out);
-
-  // There should be one change to the rewritten header.
-  ASSERT_TRUE(ChangeTypeMatches(out, {SyncChange::ACTION_UPDATE}));
-  VerifyLocalHeaderChange(out[0], 1, 1);
-
-  // SessionId should not be rewritten on restore.
-  int restored_tab_id =
-      out[0].sync_data().GetSpecifics().session().header().window(0).tab(0);
-  EXPECT_EQ(tab->GetSessionId().id(), restored_tab_id);
-  out.clear();
-
-  // Now actually resurrect the native data, which will end up having different
-  // native ids, but the tab has the same sync id as before.
-  AddWindow()->OverrideTabAt(0, tab);
-  tab->Navigate(kBar1);
-
-  ASSERT_TRUE(ChangeTypeMatches(
-      out, {SyncChange::ACTION_UPDATE, SyncChange::ACTION_UPDATE}));
-  VerifyLocalTabChange(out[0], 3, kBar1);
-  VerifyLocalHeaderChange(out[1], 1, 1);
-}
-
-// Ensure that tabbed windows from a previous session are preserved if only
-// transient windows are present at startup.
-TEST_F(SessionsSyncManagerTest, PreserveTabbedDataCustomTab) {
-  syncer::SyncDataList in;
-  syncer::SyncChangeList out;
-
-  // Set up one tab and start sync with it.
-  TestSyncedWindowDelegate* window = AddWindow();
-  TestSyncedTabDelegate* tab = AddTab(window->GetSessionId(), kFoo1);
-  tab->Navigate(kFoo2);
-  InitWithSyncDataTakeOutput(in, &out);
-
-  // There should be two entities, a header and a tab.
-  in = GetDataFromChanges(out);
-  out.clear();
-  ASSERT_EQ(2U, in.size());
-
-  // Resync, using the previous sync data, but with only a custom tab open.
-  manager()->StopSyncing(syncer::SESSIONS);
-  ResetWindows();
-  window = AddWindow(sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB);
-  AddTab(window->GetSessionId(), kBar1);
-  InitWithSyncDataTakeOutput(ConvertToRemote(in), &out);
-
-  // The previous session should be preserved, together with the new custom tab.
-  ASSERT_TRUE(ChangeTypeMatches(
-      out, {SyncChange::ACTION_ADD, SyncChange::ACTION_UPDATE}));
-  VerifyLocalTabChange(out[0], 1, kBar1);
-  VerifyLocalHeaderChange(out[1], 2, 2);
-}
-
-// Tests MergeDataAndStartSyncing with sync data but no local data.
-TEST_F(SessionsSyncManagerTest, MergeWithInitialForeignSession) {
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession(kTag1, kTabIds1, &tabs1));
-  // Add a second window.
-  helper()->AddWindowSpecifics(kWindowId2, kTabIds2, &meta);
-
-  // Set up initial data.
-  SyncDataList initial_data;
-  initial_data.push_back(CreateRemoteData(meta));
-  AddTabsToSyncDataList(tabs1, &initial_data);
-  for (auto tab_id : kTabIds2) {
-    sync_pb::EntitySpecifics entity;
-    helper()->BuildTabSpecifics(kTag1, kWindowId1, tab_id,
-                                entity.mutable_session());
-    initial_data.push_back(CreateRemoteData(entity));
-  }
-
-  SyncChangeList output;
-  InitWithSyncDataTakeOutput(initial_data, &output);
-  EXPECT_TRUE(FilterOutLocalHeaderChanges(&output)->empty());
-
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(1U, foreign_sessions.size());
-  std::vector<std::vector<SessionID>> session_reference;
-  session_reference.push_back(kTabIds1);
-  session_reference.push_back(kTabIds2);
-  helper()->VerifySyncedSession(kTag1, session_reference,
-                                *(foreign_sessions[0]));
-}
-
-// Ensure model association associates the pre-existing tabs.
-TEST_F(SessionsSyncManagerTest, MergeLocalSessionExistingTabs) {
-  TestSyncedWindowDelegate* window = AddWindow();
-  SessionID window_id = window->GetSessionId();
-  TestSyncedTabDelegate* tab = AddTab(window_id, kFoo1);
-  tab->Navigate(kBar1);  // Adds back entry.
-  tab->Navigate(kBaz1);  // Adds back entry.
-  TestSyncedTabDelegate* tab2 = AddTab(window_id, kFoo2);
-  tab2->Navigate(kBar2);  // Adds back entry.
-
-  SyncChangeList out;
-  InitWithSyncDataTakeOutput(SyncDataList(), &out);
-  // Header creation, add two tabs, header update.
-  ASSERT_TRUE(
-      ChangeTypeMatches(out,
-                        {SyncChange::ACTION_ADD, SyncChange::ACTION_ADD,
-                         SyncChange::ACTION_ADD, SyncChange::ACTION_UPDATE}));
-  EXPECT_EQ(out.size(),
-            CountIfTagMatches(out, manager()->current_machine_tag()));
-
-  // Check that this machine's data is not included in the foreign windows.
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_FALSE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-
-  VerifyLocalHeaderChange(out[0], 0, 0);
-  VerifyLocalTabChange(out[1], tab->GetEntryCount(), kBaz1);
-  VerifyLocalTabChange(out[2], tab2->GetEntryCount(), kBar2);
-  VerifyLocalHeaderChange(out[3], 1, 2);
-}
-
-// Ensure that the last known device name is reported.
-TEST_F(SessionsSyncManagerTest, MergeLocalSessionName) {
-  const std::string kModifiedDeviceName = "New Device Name";
-
-  SyncChangeList out;
-  InitWithSyncDataTakeOutput(SyncDataList(), &out);
-  syncer::SyncDataList initial_data = GetDataFromChanges(out);
-  // Local header expected.
-  ASSERT_EQ(1U, initial_data.size());
-
-  // Change local device name to |kModifiedDeviceName|.
-  const DeviceInfo new_device_info(
-      kCacheGuid, kModifiedDeviceName, "Chromium 10k", "Chrome 10k",
-      sync_pb::SyncEnums_DeviceType_TYPE_LINUX, "device_id");
-  ON_CALL(*mock_sync_sessions_client(), GetLocalDeviceInfo())
-      .WillByDefault(testing::Return(&new_device_info));
-
-  // Restart the manager, now that the local device name has changed.
-  manager()->StopSyncing(syncer::SESSIONS);
-  out.clear();
-  InitWithSyncDataTakeOutput(ConvertToRemote(initial_data), &out);
-
-  EXPECT_EQ(kModifiedDeviceName, manager()->GetCurrentSessionNameForTest());
-}
-
-// This is a combination of MergeWithInitialForeignSession and
-// MergeLocalSessionExistingTabs. We repeat some checks performed in each of
-// those tests to ensure the common mixed scenario works.
-TEST_F(SessionsSyncManagerTest, MergeWithLocalAndForeignTabs) {
-  // Local.
-  TestSyncedTabDelegate* tab = AddTab(AddWindow()->GetSessionId(), kFoo1);
-  tab->Navigate(kFoo2);
-
-  // Foreign.
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession(kTag1, kTabIds1, &tabs1));
-  SyncDataList foreign_data;
-  foreign_data.push_back(CreateRemoteData(meta));
-  AddTabsToSyncDataList(tabs1, &foreign_data);
-
-  SyncChangeList out;
-  InitWithSyncDataTakeOutput(foreign_data, &out);
-
-  // Should be one header add, 1 tab add, and one header update.
-  ASSERT_TRUE(ChangeTypeMatches(out,
-                                {SyncChange::ACTION_ADD, SyncChange::ACTION_ADD,
-                                 SyncChange::ACTION_UPDATE}));
-  EXPECT_EQ(out.size(),
-            CountIfTagMatches(out, manager()->current_machine_tag()));
-
-  // Verify local data.
-  VerifyLocalHeaderChange(out[0], 0, 0);
-  VerifyLocalTabChange(out[1], tab->GetEntryCount(), kFoo2);
-  VerifyLocalHeaderChange(out[2], 1, 1);
-
-  // Verify foreign data.
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  std::vector<std::vector<SessionID>> session_reference;
-  session_reference.push_back(kTabIds1);
-  helper()->VerifySyncedSession(kTag1, session_reference,
-                                *(foreign_sessions[0]));
-  // There should be one and only one foreign session. If VerifySyncedSession
-  // was successful above this EXPECT call ensures the local session didn't
-  // get mistakenly added to foreign tracking (Similar to ExistingTabs test).
-  EXPECT_EQ(1U, foreign_sessions.size());
-}
-
-// Tests the common scenario.  Merge with both local and foreign session data
-// followed by updates flowing from sync and local.
-TEST_F(SessionsSyncManagerTest, UpdatesAfterMixedMerge) {
-  // Add local and foreign data.
-  TestSyncedTabDelegate* tab = AddTab(AddWindow()->GetSessionId(), kFoo1);
-  tab->Navigate(kFoo2);
-  AddTab(AddWindow()->GetSessionId(), kBar1);
-
-  SyncDataList foreign_data1;
-  std::vector<std::vector<SessionID>> meta1_reference;
-  sync_pb::SessionSpecifics meta1;
-
-  meta1_reference.push_back(kTabIds1);
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  meta1 = helper()->BuildForeignSession(kTag1, kTabIds1, &tabs1);
-  foreign_data1.push_back(CreateRemoteData(meta1));
-  AddTabsToSyncDataList(tabs1, &foreign_data1);
-
-  SyncChangeList out;
-  InitWithSyncDataTakeOutput(foreign_data1, &out);
-
-  // 1 header add, two tab adds, one header update.
-  ASSERT_TRUE(
-      ChangeTypeMatches(out,
-                        {SyncChange::ACTION_ADD, SyncChange::ACTION_ADD,
-                         SyncChange::ACTION_ADD, SyncChange::ACTION_UPDATE}));
-  EXPECT_EQ(out.size(),
-            CountIfTagMatches(out, manager()->current_machine_tag()));
-  VerifyLocalHeaderChange(out[3], 2, 2);
-
-  // Add a second window to the foreign session.
-  meta1_reference.push_back(kTabIds2);
-  helper()->AddWindowSpecifics(kWindowId2, kTabIds2, &meta1);
-  std::vector<sync_pb::SessionSpecifics> tabs2;
-  tabs2.resize(kTabIds2.size());
-  for (size_t i = 0; i < kTabIds2.size(); ++i) {
-    helper()->BuildTabSpecifics(kTag1, kWindowId2, kTabIds2[i], &tabs2[i]);
-  }
-
-  SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(meta1, SyncChange::ACTION_UPDATE));
-  AddTabsToChangeList(tabs2, SyncChange::ACTION_ADD, &changes);
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-  changes.clear();
-
-  // Check that the foreign session was associated and retrieve the data.
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(1U, foreign_sessions.size());
-  ASSERT_EQ(4U, foreign_sessions[0]
-                    ->windows.find(kWindowId1)
-                    ->second->wrapped_window.tabs.size());
-  ASSERT_EQ(4U, foreign_sessions[0]
-                    ->windows.find(kWindowId2)
-                    ->second->wrapped_window.tabs.size());
-  helper()->VerifySyncedSession(kTag1, meta1_reference, *(foreign_sessions[0]));
-
-  // Add a new foreign session.
-  const std::vector<SessionID> tag2_tab_list = SessionIDs({107, 115});
-  std::vector<sync_pb::SessionSpecifics> tag2_tabs;
-  sync_pb::SessionSpecifics meta2(
-      helper()->BuildForeignSession(kTag2, tag2_tab_list, &tag2_tabs));
-  changes.push_back(MakeRemoteChange(meta2, SyncChange::ACTION_ADD));
-  AddTabsToChangeList(tag2_tabs, SyncChange::ACTION_ADD, &changes);
-
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-  changes.clear();
-
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  std::vector<std::vector<SessionID>> meta2_reference;
-  meta2_reference.push_back(tag2_tab_list);
-  ASSERT_EQ(2U, foreign_sessions.size());
-  ASSERT_EQ(2U, foreign_sessions[1]
-                    ->windows.find(kWindowId1)
-                    ->second->wrapped_window.tabs.size());
-  helper()->VerifySyncedSession(kTag2, meta2_reference, *(foreign_sessions[1]));
-  foreign_sessions.clear();
-
-  // Remove a tab from a window.
-  meta1_reference[0].pop_back();
-  sync_pb::SessionWindow* win = meta1.mutable_header()->mutable_window(0);
-  win->clear_tab();
-  for (auto iter = kTabIds1.begin(); iter + 1 != kTabIds1.end(); ++iter) {
-    win->add_tab(iter->id());
-  }
-  SyncChangeList removal;
-  removal.push_back(MakeRemoteChange(meta1, SyncChange::ACTION_UPDATE));
-  AddTabsToChangeList(tabs1, SyncChange::ACTION_UPDATE, &removal);
-  manager()->ProcessSyncChanges(FROM_HERE, removal);
-
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(2U, foreign_sessions.size());
-  ASSERT_EQ(3U, foreign_sessions[0]
-                    ->windows.find(kWindowId1)
-                    ->second->wrapped_window.tabs.size());
-  helper()->VerifySyncedSession(kTag1, meta1_reference, *(foreign_sessions[0]));
-}
-
-// Tests that this SyncSessionManager knows how to delete foreign sessions
-// if it wants to.
-TEST_F(SessionsSyncManagerTest, DeleteForeignSession) {
-  InitWithNoSyncData();
-  SyncChangeList changes;
-
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_FALSE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  manager()->DeleteForeignSessionInternal(kTag1, &changes);
-  ASSERT_FALSE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  EXPECT_TRUE(changes.empty());
-
-  // Fill an instance of session specifics with a foreign session's data.
-  std::vector<sync_pb::SessionSpecifics> tabs;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession(kTag1, kTabIds1, &tabs));
-
-  // Update associator with the session's meta node, window, and tabs.
-  UpdateTrackerWithSpecifics(meta, base::Time(), &manager()->session_tracker_);
-  for (auto iter = tabs.begin(); iter != tabs.end(); ++iter) {
-    UpdateTrackerWithSpecifics(*iter, base::Time(),
-                               &manager()->session_tracker_);
-  }
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(1U, foreign_sessions.size());
-
-  // Now delete the foreign session.
-  manager()->DeleteForeignSessionInternal(kTag1, &changes);
-  EXPECT_FALSE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-
-  EXPECT_EQ(5U, changes.size());
-  ASSERT_TRUE(AllOfChangesAreType(changes, SyncChange::ACTION_DELETE));
-  std::set<std::string> expected_tags(&kTag1, &kTag1 + 1);
-  for (int i = 0; i < 5; ++i)
-    expected_tags.insert(TabNodeIdToTag(kTag1, i));
-
-  for (int i = 0; i < 5; ++i) {
-    SCOPED_TRACE(changes[i].ToString());
-    EXPECT_TRUE(changes[i].IsValid());
-    EXPECT_TRUE(changes[i].sync_data().IsValid());
-    EXPECT_EQ(1U, expected_tags.erase(
-                      SyncDataLocal(changes[i].sync_data()).GetTag()));
-  }
-}
-
-// Write a foreign session to a node, with the tabs arriving first, and then
-// retrieve it.
-TEST_F(SessionsSyncManagerTest, WriteForeignSessionToNodeTabsFirst) {
-  InitWithNoSyncData();
-
-  // Fill an instance of session specifics with a foreign session's data.
-  std::string tag = "tag1";
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession(tag, kTabIds1, &tabs1));
-
-  SyncChangeList adds;
-  // Add tabs for first window, then the meta node.
-  AddTabsToChangeList(tabs1, SyncChange::ACTION_ADD, &adds);
-  adds.push_back(MakeRemoteChange(meta, SyncChange::ACTION_ADD));
-  manager()->ProcessSyncChanges(FROM_HERE, adds);
-
-  // Check that the foreign session was associated and retrieve the data.
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(1U, foreign_sessions.size());
-  std::vector<std::vector<SessionID>> session_reference;
-  session_reference.push_back(kTabIds1);
-  helper()->VerifySyncedSession(tag, session_reference, *(foreign_sessions[0]));
-}
-
-// Write a foreign session to a node with some tabs that never arrive.
-TEST_F(SessionsSyncManagerTest, WriteForeignSessionToNodeMissingTabs) {
-  InitWithNoSyncData();
-
-  // Fill an instance of session specifics with a foreign session's data.
-  std::string tag = "tag1";
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession(tag, kTabIds1, &tabs1));
-  // Add a second window, but this time only create two tab nodes, despite the
-  // window expecting four tabs.
-  helper()->AddWindowSpecifics(kWindowId2, kTabIds2, &meta);
-  std::vector<sync_pb::SessionSpecifics> tabs2;
-  tabs2.resize(2);
-  for (size_t i = 0; i < 2; ++i) {
-    helper()->BuildTabSpecifics(tag, kWindowId1, kTabIds2[i], &tabs2[i]);
-  }
-
-  SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_ADD));
-  AddTabsToChangeList(tabs1, SyncChange::ACTION_ADD, &changes);
-  AddTabsToChangeList(tabs2, SyncChange::ACTION_ADD, &changes);
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-  changes.clear();
-
-  // Check that the foreign session was associated and retrieve the data.
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(1U, foreign_sessions.size());
-  ASSERT_EQ(2U, foreign_sessions[0]->windows.size());
-  ASSERT_EQ(4U, foreign_sessions[0]
-                    ->windows.find(kWindowId1)
-                    ->second->wrapped_window.tabs.size());
-  ASSERT_EQ(4U, foreign_sessions[0]
-                    ->windows.find(kWindowId2)
-                    ->second->wrapped_window.tabs.size());
-
-  // Close the second window.
-  meta.mutable_header()->clear_window();
-  helper()->AddWindowSpecifics(kWindowId1, kTabIds1, &meta);
-  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_UPDATE));
-  // Update associator with the session's meta node containing one window.
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-
-  // Check that the foreign session was associated and retrieve the data.
-  foreign_sessions.clear();
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(1U, foreign_sessions.size());
-  ASSERT_EQ(1U, foreign_sessions[0]->windows.size());
-  std::vector<std::vector<SessionID>> session_reference;
-  session_reference.push_back(kTabIds1);
-  helper()->VerifySyncedSession(tag, session_reference, *(foreign_sessions[0]));
-}
-
-// Tests that the SessionsSyncManager can handle a remote client deleting
-// sync nodes that belong to this local session.
-TEST_F(SessionsSyncManagerTest, ProcessRemoteDeleteOfLocalSession) {
-  SessionID window_id = AddWindow()->GetSessionId();
-  SyncChangeList out;
-  InitWithSyncDataTakeOutput(SyncDataList(), &out);
-  ASSERT_EQ(2U, out.size());
-
-  SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(
-      out[1].sync_data().GetSpecifics().session(), SyncChange::ACTION_DELETE));
-  out.clear();
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-  EXPECT_TRUE(manager()->local_tab_pool_out_of_sync_);
-  EXPECT_TRUE(out.empty());  // ChangeProcessor shouldn't see any activity.
-
-  // This should trigger repair of the TabNodePool.
-  AddTab(window_id, kFoo1);
-  EXPECT_FALSE(manager()->local_tab_pool_out_of_sync_);
-
-  // Rebuilding associations will trigger an initial header add and update,
-  // coupled with the tab creation and the header update to reflect the new tab.
-  // In total, that means four changes.
-  ASSERT_TRUE(
-      ChangeTypeMatches(out,
-                        {SyncChange::ACTION_ADD, SyncChange::ACTION_UPDATE,
-                         SyncChange::ACTION_ADD, SyncChange::ACTION_UPDATE}));
-
-  // Verify the actual content.
-  VerifyLocalTabChange(out[2], 1, kFoo1);
-  VerifyLocalHeaderChange(out[3], 1, 1);
-
-  // Verify TabLinks.
-  int tab_node_id = out[2].sync_data().GetSpecifics().session().tab_node_id();
-  int tab_id = out[2].sync_data().GetSpecifics().session().tab().tab_id();
-  EXPECT_EQ(tab_id, manager()
-                        ->session_tracker_
-                        .LookupTabIdFromTabNodeId(
-                            manager()->current_machine_tag(), tab_node_id)
-                        .id());
-}
-
-// Test that receiving a session delete from sync removes the session
-// from tracking.
-TEST_F(SessionsSyncManagerTest, ProcessForeignDelete) {
-  InitWithNoSyncData();
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession("tag1", kTabIds1, &tabs1));
-
-  SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_ADD));
-  AddTabsToChangeList(tabs1, SyncChange::ACTION_ADD, &changes);
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(1U, foreign_sessions.size());
-
-  changes.clear();
-  foreign_sessions.clear();
-  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_DELETE));
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-
-  EXPECT_FALSE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-}
-
-TEST_F(SessionsSyncManagerTest, ProcessForeignDeleteTabs) {
-  SyncDataList foreign_data;
-  base::Time stale_mtime = base::Time::Now() - base::TimeDelta::FromDays(15);
-  std::string session_tag = "tag1";
-
-  // 1 will not have ownership changed.
-  // 2 will not be updated, but header will stop owning.
-  // 3 will be deleted before header stops owning.
-  // 4 will be deleted after header stops owning.
-  // 5 will be deleted before header update, but header will still try to own.
-  // 6 will be deleted after header update, but header will still try to own.
-  // 7 starts orphaned and then deleted before header update.
-  // 8 starts orphaned and then deleted after header update.
-  const std::vector<SessionID> tab_list = SessionIDs({1, 2, 3, 4, 5, 6});
-  std::vector<sync_pb::SessionSpecifics> tabs;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession(session_tag, tab_list, &tabs));
-  AddToSyncDataList(meta, &foreign_data, stale_mtime);
-  AddTabsToSyncDataList(tabs, &foreign_data);
-  sync_pb::SessionSpecifics orphan6;
-  helper()->BuildTabSpecifics(session_tag, kWindowId1,
-                              SessionID::FromSerializedValue(6), &orphan6);
-  AddToSyncDataList(orphan6, &foreign_data, stale_mtime);
-  sync_pb::SessionSpecifics orphan7;
-  helper()->BuildTabSpecifics(session_tag, kWindowId1,
-                              SessionID::FromSerializedValue(7), &orphan7);
-  AddToSyncDataList(orphan7, &foreign_data, stale_mtime);
-
-  AddWindow();
-  SyncChangeList output;
-  InitWithSyncDataTakeOutput(foreign_data, &output);
-  ASSERT_EQ(2U, output.size());
-  output.clear();
-
-  const std::vector<SessionID> update_list = SessionIDs({1, 5, 6});
-  sync_pb::SessionWindow* window = meta.mutable_header()->mutable_window(0);
-  window->clear_tab();
-  for (SessionID i : update_list) {
-    window->add_tab(i.id());
-  }
-
-  SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(tabs[2], SyncChange::ACTION_DELETE));
-  changes.push_back(MakeRemoteChange(tabs[4], SyncChange::ACTION_DELETE));
-  changes.push_back(MakeRemoteChange(orphan6, SyncChange::ACTION_DELETE));
-  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_UPDATE));
-  changes.push_back(MakeRemoteChange(tabs[3], SyncChange::ACTION_DELETE));
-  changes.push_back(MakeRemoteChange(tabs[5], SyncChange::ACTION_DELETE));
-  changes.push_back(MakeRemoteChange(orphan7, SyncChange::ACTION_DELETE));
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(1U, foreign_sessions.size());
-  std::vector<std::vector<SessionID>> session_reference;
-  session_reference.push_back(update_list);
-  helper()->VerifySyncedSession(session_tag, session_reference,
-                                *(foreign_sessions[0]));
-
-  // Everything except for session, tab0, and tab1 will have no node_id, and
-  // should get skipped by garbage collection.
-  manager()->DoGarbageCollection();
-  ASSERT_EQ(3U, output.size());
-}
-
-TEST_F(SessionsSyncManagerTest, ProcessForeignDeleteTabsWithShadowing) {
-  SyncDataList foreign_data;
-  base::Time stale_mtime = base::Time::Now() - base::TimeDelta::FromDays(16);
-  std::string session_tag = "tag1";
-
-  // Add several tabs that shadow eachother, in that they share tab_ids. They
-  // will, thanks to the helper, have unique tab_node_ids.
-  sync_pb::SessionSpecifics tab1A;
-  helper()->BuildTabSpecifics(session_tag, kWindowId1, kTabIds1[0], &tab1A);
-  AddToSyncDataList(tab1A, &foreign_data,
-                    stale_mtime + base::TimeDelta::FromMinutes(1));
-
-  sync_pb::SessionSpecifics tab1B;
-  helper()->BuildTabSpecifics(session_tag, kWindowId1, kTabIds1[0], &tab1B);
-  AddToSyncDataList(tab1B, &foreign_data,
-                    stale_mtime + base::TimeDelta::FromMinutes(2));
-
-  sync_pb::SessionSpecifics tab1C;
-  helper()->BuildTabSpecifics(session_tag, kWindowId1, kTabIds1[0], &tab1C);
-  AddToSyncDataList(tab1C, &foreign_data, stale_mtime);
-
-  sync_pb::SessionSpecifics tab2A;
-  helper()->BuildTabSpecifics(session_tag, kWindowId1, kTabIds1[1], &tab2A);
-  AddToSyncDataList(tab2A, &foreign_data,
-                    stale_mtime + base::TimeDelta::FromMinutes(1));
-
-  sync_pb::SessionSpecifics tab2B;
-  helper()->BuildTabSpecifics(session_tag, kWindowId1, kTabIds1[1], &tab2B);
-  AddToSyncDataList(tab2B, &foreign_data,
-                    stale_mtime + base::TimeDelta::FromMinutes(2));
-
-  sync_pb::SessionSpecifics tab2C;
-  helper()->BuildTabSpecifics(session_tag, kWindowId1, kTabIds1[1], &tab2C);
-  AddToSyncDataList(tab2C, &foreign_data, stale_mtime);
-
-  AddWindow();
-  SyncChangeList output;
-  InitWithSyncDataTakeOutput(foreign_data, &output);
-  ASSERT_EQ(2U, output.size());
-  output.clear();
-
-  // Verify that cleanup post-merge cleanup correctly removes all tabs objects.
-  ASSERT_THAT(
-      manager()->session_tracker_.LookupSessionTab(session_tag, kTabIds1[0]),
-      IsNull());
-  ASSERT_THAT(
-      manager()->session_tracker_.LookupSessionTab(session_tag, kTabIds1[1]),
-      IsNull());
-
-  EXPECT_THAT(manager()->session_tracker_.LookupTabNodeIds(session_tag),
-              ElementsAre(tab1A.tab_node_id(), tab1B.tab_node_id(),
-                          tab1C.tab_node_id(), tab2A.tab_node_id(),
-                          tab2B.tab_node_id(), tab2C.tab_node_id()));
-
-  SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(tab1A, SyncChange::ACTION_DELETE));
-  changes.push_back(MakeRemoteChange(tab1B, SyncChange::ACTION_DELETE));
-  changes.push_back(MakeRemoteChange(tab2C, SyncChange::ACTION_DELETE));
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-
-  EXPECT_THAT(manager()->session_tracker_.LookupTabNodeIds(session_tag),
-              ElementsAre(tab1C.tab_node_id(), tab2A.tab_node_id(),
-                          tab2B.tab_node_id()));
-
-  manager()->DoGarbageCollection();
-  ASSERT_EQ(3U, output.size());
-}
-
-TEST_F(SessionsSyncManagerTest, ProcessForeignDeleteTabsWithReusedNodeIds) {
-  SyncDataList foreign_data;
-  base::Time stale_mtime = base::Time::Now() - base::TimeDelta::FromDays(16);
-  std::string session_tag = "tag1";
-  int tab_node_id_shared = 13;
-  int tab_node_id_unique = 14;
-
-  sync_pb::SessionSpecifics tab1A;
-  helper()->BuildTabSpecifics(session_tag, kWindowId1, kTabIds1[1],
-                              tab_node_id_shared, &tab1A);
-  AddToSyncDataList(tab1A, &foreign_data,
-                    stale_mtime + base::TimeDelta::FromMinutes(1));
-
-  sync_pb::SessionSpecifics tab1B;
-  helper()->BuildTabSpecifics(session_tag, kWindowId1, kTabIds1[1],
-                              tab_node_id_unique, &tab1B);
-  AddToSyncDataList(tab1B, &foreign_data,
-                    stale_mtime + base::TimeDelta::FromMinutes(2));
-
-  sync_pb::SessionSpecifics tab2A;
-  helper()->BuildTabSpecifics(session_tag, kWindowId1, kTabIds1[2],
-                              tab_node_id_shared, &tab2A);
-  AddToSyncDataList(tab2A, &foreign_data,
-                    stale_mtime + base::TimeDelta::FromMinutes(1));
-
-  AddWindow();
-  SyncChangeList output;
-  InitWithSyncDataTakeOutput(foreign_data, &output);
-  ASSERT_EQ(2U, output.size());
-  output.clear();
-
-  EXPECT_THAT(manager()->session_tracker_.LookupTabNodeIds(session_tag),
-              ElementsAre(tab_node_id_shared, tab_node_id_unique));
-
-  SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(tab1A, SyncChange::ACTION_DELETE));
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-
-  EXPECT_THAT(manager()->session_tracker_.LookupTabNodeIds(session_tag),
-              ElementsAre(tab_node_id_unique));
-
-  manager()->DoGarbageCollection();
-  EXPECT_EQ(1U, output.size());
-}
-
-TEST_F(SessionsSyncManagerTest, AssociationReusesNodes) {
-  SyncChangeList changes;
-  TestSyncedWindowDelegate* window = AddWindow();
-  TestSyncedTabDelegate* tab = AddTab(window->GetSessionId(), kFoo1);
-  InitWithSyncDataTakeOutput(SyncDataList(), &changes);
-  ASSERT_TRUE(ChangeTypeMatches(changes,
-                                {SyncChange::ACTION_ADD, SyncChange::ACTION_ADD,
-                                 SyncChange::ACTION_UPDATE}));
-  ASSERT_TRUE(changes[1].sync_data().GetSpecifics().session().has_tab());
-  int tab_node_id =
-      changes[1].sync_data().GetSpecifics().session().tab_node_id();
-
-  // Pass back the previous tab and header nodes at association, along with a
-  // second tab node (with rewritten tab IDs).
-  SyncDataList in;
-  in.push_back(
-      CreateRemoteData(changes[2].sync_data().GetSpecifics()));  // Header node.
-  sync_pb::SessionSpecifics new_tab(
-      changes[1].sync_data().GetSpecifics().session());
-  new_tab.mutable_tab()->set_tab_id(new_tab.tab().tab_id() + 1);
-  new_tab.set_tab_node_id(tab_node_id + 1);
-  in.push_back(CreateRemoteData(
-      changes[1].sync_data().GetSpecifics()));  // Old tab node.
-  in.push_back(CreateRemoteData(new_tab));      // New tab node.
-  changes.clear();
-
-  // Reassociate (with the same single tab/window open).
-  manager()->StopSyncing(syncer::SESSIONS);
-  InitWithSyncDataTakeOutput(in, &changes);
-
-  // No tab entities should be deleted. The original (lower) tab node id should
-  // be reused for association.
-  FilterOutLocalHeaderChanges(&changes);
-  ASSERT_TRUE(ChangeTypeMatches(changes, {SyncChange::ACTION_UPDATE}));
-  VerifyLocalTabChange(changes[0], 1, kFoo1);
-  EXPECT_EQ(tab_node_id,
-            changes[0].sync_data().GetSpecifics().session().tab_node_id());
-  changes.clear();
-
-  // Update the original tab. Ensure the same tab node is updated.
-  tab->Navigate(kFoo2);
-  FilterOutLocalHeaderChanges(&changes);
-  ASSERT_TRUE(ChangeTypeMatches(changes, {SyncChange::ACTION_UPDATE}));
-  VerifyLocalTabChange(changes[0], 2, kFoo2);
-  EXPECT_EQ(tab_node_id,
-            changes[0].sync_data().GetSpecifics().session().tab_node_id());
-  changes.clear();
-
-  // Add a new tab. It should reuse the second tab node.
-  AddTab(window->GetSessionId(), kBar1);
-  FilterOutLocalHeaderChanges(&changes);
-  ASSERT_TRUE(ChangeTypeMatches(changes, {SyncChange::ACTION_UPDATE}));
-  VerifyLocalTabChange(changes[0], 1, kBar1);
-  EXPECT_EQ(tab_node_id + 1,
-            changes[0].sync_data().GetSpecifics().session().tab_node_id());
-}
-
-// Ensure that the merge process deletes a tab node without a tab id.
-TEST_F(SessionsSyncManagerTest, MergeDeletesTabMissingTabId) {
-  SyncChangeList changes;
-  InitWithNoSyncData();
-
-  std::string local_tag = manager()->current_machine_tag();
-  int tab_node_id = 0;
-  sync_pb::SessionSpecifics specifics;
-  specifics.set_session_tag(local_tag);
-  specifics.set_tab_node_id(tab_node_id);
-  manager()->StopSyncing(syncer::SESSIONS);
-  InitWithSyncDataTakeOutput({CreateRemoteData(specifics)}, &changes);
-  EXPECT_EQ(1U, FilterOutLocalHeaderChanges(&changes)->size());
-  EXPECT_EQ(SyncChange::ACTION_DELETE, changes[0].change_type());
-  EXPECT_EQ(TabNodeIdToTag(local_tag, tab_node_id),
-            SyncDataLocal(changes[0].sync_data()).GetTag());
-}
-
-// Verifies that we drop both headers and tabs during merge if their stored tag
-// hash doesn't match a computer tag hash. This mitigates potential failures
-// while cleaning up bad foreign data, see https://crbug.com/604657.
-TEST_F(SessionsSyncManagerTest, MergeDeletesBadHash) {
-  SyncDataList foreign_data;
-  std::vector<SessionID> empty_ids;
-  std::vector<sync_pb::SessionSpecifics> empty_tabs;
-  sync_pb::EntitySpecifics entity;
-
-  const std::string good_header_tag = "good_header_tag";
-  sync_pb::SessionSpecifics good_header(
-      helper()->BuildForeignSession(good_header_tag, empty_ids, &empty_tabs));
-  foreign_data.push_back(CreateRemoteData(good_header));
-
-  const std::string bad_header_tag = "bad_header_tag";
-  sync_pb::SessionSpecifics bad_header(
-      helper()->BuildForeignSession(bad_header_tag, empty_ids, &empty_tabs));
-  entity.mutable_session()->CopyFrom(bad_header);
-  foreign_data.push_back(SyncData::CreateRemoteData(1, entity, base::Time(),
-                                                    "bad_header_tag_hash"));
-
-  const std::string good_tag_tab = "good_tag_tab";
-  sync_pb::SessionSpecifics good_tab;
-  helper()->BuildTabSpecifics(good_tag_tab, kWindowId1, kTabIds1[0], &good_tab);
-  foreign_data.push_back(CreateRemoteData(good_tab));
-
-  const std::string bad_tab_tag = "bad_tab_tag";
-  sync_pb::SessionSpecifics bad_tab;
-  helper()->BuildTabSpecifics(bad_tab_tag, kWindowId1, kTabIds1[1], &bad_tab);
-  entity.mutable_session()->CopyFrom(bad_tab);
-  foreign_data.push_back(
-      SyncData::CreateRemoteData(1, entity, base::Time(), "bad_tab_tag_hash"));
-
-  SyncChangeList output;
-  InitWithSyncDataTakeOutput(foreign_data, &output);
-  ASSERT_EQ(2U, FilterOutLocalHeaderChanges(&output)->size());
-  ASSERT_TRUE(AllOfChangesAreType(output, SyncChange::ACTION_DELETE));
-  EXPECT_EQ(1U, CountIfTagMatches(output, bad_header_tag));
-  EXPECT_EQ(1U, CountIfTagMatches(output, bad_tab_tag));
-
-  const std::vector<const SyncedSession*> sessions =
-      manager()->session_tracker_.LookupAllForeignSessions(
-          SyncedSessionTracker::RAW);
-  ASSERT_EQ(2U, sessions.size());
-  EXPECT_EQ(1U, CountIfTagMatches(sessions, good_header_tag));
-  EXPECT_EQ(1U, CountIfTagMatches(sessions, good_tag_tab));
-}
-
-// Test that things work if a tab is initially ignored.
-TEST_F(SessionsSyncManagerTest, AssociateWindowsDontReloadTabs) {
-  SyncChangeList out;
-  // Go to a URL that is ignored by session syncing.
-  TestSyncedTabDelegate* tab =
-      AddTab(AddWindow()->GetSessionId(), "chrome://preferences/");
-  InitWithSyncDataTakeOutput(SyncDataList(), &out);
-  ASSERT_TRUE(ChangeTypeMatches(
-      out, {SyncChange::ACTION_ADD, SyncChange::ACTION_UPDATE}));
-  VerifyLocalHeaderChange(out[1], 0, 0);
-  out.clear();
-
-  // Go to a sync-interesting URL.
-  tab->Navigate(kFoo1);
-
-  // The tab should be created, coupled with a header update.
-  ASSERT_TRUE(ChangeTypeMatches(
-      out, {SyncChange::ACTION_ADD, SyncChange::ACTION_UPDATE}));
-  VerifyLocalTabChange(out[0], 2, kFoo1);
-  VerifyLocalHeaderChange(out[1], 1, 1);
-}
-
-// Tests that the SyncSessionManager responds to local tab events properly.
-TEST_F(SessionsSyncManagerTest, OnLocalTabModified) {
-  SyncChangeList out;
-  // Init with no local data, relies on MergeLocalSessionNoTabs.
-  TestSyncedWindowDelegate* window = AddWindow();
-  SessionID window_id = window->GetSessionId();
-  InitWithSyncDataTakeOutput(SyncDataList(), &out);
-  ASSERT_FALSE(manager()->current_machine_tag().empty());
-  ASSERT_EQ(2U, out.size());
-
-  // Copy the original header.
-  sync_pb::EntitySpecifics header(out[0].sync_data().GetSpecifics());
-  out.clear();
-
-  AddTab(window_id, kFoo1)->Navigate(kFoo2);
-  AddTab(window_id, kBar1)->Navigate(kBar2);
-  std::vector<std::string> urls = {kFoo1, kFoo2, kBar1, kBar2};
-
-  // Change type breakdown:
-  // 1 tab add + 2 header updates.
-  const size_t kChangesPerTabCreation = 3;
-  // 1 tab update + 1 header update.
-  const size_t kChangesPerTabNav = 2;
-  const size_t kChangesPerTab = kChangesPerTabNav + kChangesPerTabCreation;
-  const size_t kNumTabs = 2;
-  const size_t kTotalUpdates = kChangesPerTab * kNumTabs;
-
-  std::vector<SyncChange::SyncChangeType> types = {
-      // Tab 1
-      SyncChange::ACTION_UPDATE, SyncChange::ACTION_ADD,
-      SyncChange::ACTION_UPDATE, SyncChange::ACTION_UPDATE,
-      SyncChange::ACTION_UPDATE,
-      // Tab 2
-      SyncChange::ACTION_UPDATE, SyncChange::ACTION_ADD,
-      SyncChange::ACTION_UPDATE, SyncChange::ACTION_UPDATE,
-      SyncChange::ACTION_UPDATE};
-  ASSERT_EQ(kTotalUpdates, types.size());
-
-  // Verify the tab node creations and updates to ensure the SyncProcessor sees
-  // the right operations. Do this by inspecting the set of changes for each
-  // tab separately by iterating through the tabs.
-  ASSERT_TRUE(ChangeTypeMatches(out, types));
-  for (size_t i = 0; i < kNumTabs; ++i) {
-    int index = kChangesPerTab * i;
-    int nav_per_tab_count = 0;
-    {
-      SCOPED_TRACE(index);
-      // The initial tab parent event triggers a header update (which is in
-      // effect a no-op).
-      VerifyLocalHeaderChange(out[index++], (i == 0 ? 0 : 1), i);
-    }
-    {
-      SCOPED_TRACE(index);
-      nav_per_tab_count++;
-      // Tab update after initial creation..
-      VerifyLocalTabChange(out[index++], nav_per_tab_count,
-                           urls[i * kChangesPerTabNav + nav_per_tab_count - 1]);
-    }
-    {
-      SCOPED_TRACE(index);
-      // The associate windows after the tab creation.
-      VerifyLocalHeaderChange(out[index++], 1, i + 1);
-    }
-    {
-      SCOPED_TRACE(index);
-      nav_per_tab_count++;
-      // Tab navigation.
-      VerifyLocalTabChange(out[index++], nav_per_tab_count,
-                           urls[i * kChangesPerTabNav + nav_per_tab_count - 1]);
-    }
-    {
-      SCOPED_TRACE(index);
-      // The associate windows after the tab navigation.
-      VerifyLocalHeaderChange(out[index++], 1, i + 1);
-    }
-  }
-}
-
-TEST_F(SessionsSyncManagerTest, ForeignSessionModifiedTime) {
-  SyncDataList foreign_data;
-  base::Time newest_time = base::Time::Now() - base::TimeDelta::FromDays(1);
-  base::Time middle_time = base::Time::Now() - base::TimeDelta::FromDays(2);
-  base::Time oldest_time = base::Time::Now() - base::TimeDelta::FromDays(3);
-
-  {
-    std::string session_tag = "tag1";
-    std::vector<sync_pb::SessionSpecifics> tabs;
-    sync_pb::SessionSpecifics meta(
-        helper()->BuildForeignSession(session_tag, SessionIDs({1, 2}), &tabs));
-    AddToSyncDataList(tabs[0], &foreign_data, newest_time);
-    AddToSyncDataList(meta, &foreign_data, middle_time);
-    AddToSyncDataList(tabs[1], &foreign_data, oldest_time);
-  }
-
-  {
-    std::string session_tag = "tag2";
-    std::vector<sync_pb::SessionSpecifics> tabs;
-    sync_pb::SessionSpecifics meta(
-        helper()->BuildForeignSession(session_tag, SessionIDs({3, 4}), &tabs));
-    AddToSyncDataList(tabs[0], &foreign_data, middle_time);
-    AddToSyncDataList(meta, &foreign_data, newest_time);
-    AddToSyncDataList(tabs[1], &foreign_data, oldest_time);
-  }
-
-  {
-    std::string session_tag = "tag3";
-    std::vector<sync_pb::SessionSpecifics> tabs;
-    sync_pb::SessionSpecifics meta(
-        helper()->BuildForeignSession(session_tag, SessionIDs({5, 6}), &tabs));
-    AddToSyncDataList(tabs[0], &foreign_data, oldest_time);
-    AddToSyncDataList(meta, &foreign_data, middle_time);
-    AddToSyncDataList(tabs[1], &foreign_data, newest_time);
-  }
-
-  SyncChangeList output;
-  AddWindow();
-  InitWithSyncDataTakeOutput(foreign_data, &output);
-  ASSERT_EQ(2U, output.size());
-  output.clear();
-
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(3U, foreign_sessions.size());
-  EXPECT_EQ(newest_time, foreign_sessions[0]->modified_time);
-  EXPECT_EQ(newest_time, foreign_sessions[1]->modified_time);
-  EXPECT_EQ(newest_time, foreign_sessions[2]->modified_time);
-}
-
-// Test garbage collection of stale foreign sessions.
-TEST_F(SessionsSyncManagerTest, DoGarbageCollection) {
-  // Fill two instances of session specifics with a foreign session's data.
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession(kTag1, kTabIds1, &tabs1));
-  std::vector<sync_pb::SessionSpecifics> tabs2;
-  sync_pb::SessionSpecifics meta2(
-      helper()->BuildForeignSession(kTag2, kTabIds2, &tabs2));
-  // Set the modification time for tag1 to be 21 days ago, tag2 to 5 days ago.
-  base::Time tag1_time = base::Time::Now() - base::TimeDelta::FromDays(21);
-  base::Time tag2_time = base::Time::Now() - base::TimeDelta::FromDays(5);
-
-  SyncDataList foreign_data;
-  foreign_data.push_back(CreateRemoteData(meta, tag1_time));
-  foreign_data.push_back(CreateRemoteData(meta2, tag2_time));
-  AddTabsToSyncDataList(tabs1, &foreign_data);
-  AddTabsToSyncDataList(tabs2, &foreign_data);
-
-  AddWindow();
-  SyncChangeList output;
-  InitWithSyncDataTakeOutput(foreign_data, &output);
-  ASSERT_EQ(2U, output.size());
-  output.clear();
-
-  // Check that the foreign session was associated and retrieve the data.
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(2U, foreign_sessions.size());
-  foreign_sessions.clear();
-
-  // Now garbage collect and verify the non-stale session is still there.
-  manager()->DoGarbageCollection();
-  ASSERT_EQ(5U, output.size());
-  ASSERT_TRUE(AllOfChangesAreType(output, SyncChange::ACTION_DELETE));
-  EXPECT_EQ(kTag1, SyncDataLocal(output[0].sync_data()).GetTag());
-  for (int i = 1; i < 5; ++i) {
-    EXPECT_EQ(TabNodeIdToTag(kTag1, i),
-              SyncDataLocal(output[i].sync_data()).GetTag());
-  }
-
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(1U, foreign_sessions.size());
-  std::vector<std::vector<SessionID>> session_reference;
-  session_reference.push_back(kTabIds2);
-  helper()->VerifySyncedSession(kTag2, session_reference,
-                                *(foreign_sessions[0]));
-}
-
-TEST_F(SessionsSyncManagerTest, DoGarbageCollectionOrphans) {
-  SyncDataList foreign_data;
-  base::Time stale_mtime = base::Time::Now() - base::TimeDelta::FromDays(15);
-
-  {
-    // A stale session with empty header
-    std::string session_tag = "tag1";
-    std::vector<sync_pb::SessionSpecifics> tabs;
-    sync_pb::SessionSpecifics meta(
-        helper()->BuildForeignSession(session_tag, {}, &tabs));
-    AddToSyncDataList(meta, &foreign_data, stale_mtime);
-  }
-
-  {
-    // A stale session with orphans w/o header
-    std::string session_tag = "tag2";
-    sync_pb::SessionSpecifics orphan;
-    helper()->BuildTabSpecifics(session_tag, kWindowId1, kTabIds1[1], &orphan);
-    AddToSyncDataList(orphan, &foreign_data, stale_mtime);
-  }
-
-  {
-    // A stale session with valid header/tab and an orphaned tab.
-    std::string session_tag = "tag3";
-    std::vector<sync_pb::SessionSpecifics> tabs;
-    sync_pb::SessionSpecifics meta(
-        helper()->BuildForeignSession(session_tag, SessionIDs({2}), &tabs));
-
-    // BuildForeignSession(...) will use a window id of 0, and we're also
-    // passing a window id of 0 to BuildTabSpecifics(...) here.  It doesn't
-    // really matter what window id we use for the orphaned tab, in the real
-    // world orphans often reference real/still valid windows, but they're
-    // orphans because the window/header doesn't reference back to them.
-    sync_pb::SessionSpecifics orphan;
-    helper()->BuildTabSpecifics(session_tag, kWindowId1, kTabIds1[1], &orphan);
-    AddToSyncDataList(orphan, &foreign_data, stale_mtime);
-
-    AddToSyncDataList(tabs[0], &foreign_data, stale_mtime);
-    AddToSyncDataList(orphan, &foreign_data, stale_mtime);
-    AddToSyncDataList(meta, &foreign_data, stale_mtime);
-  }
-
-  SyncChangeList output;
-  AddWindow();
-  InitWithSyncDataTakeOutput(foreign_data, &output);
-  ASSERT_EQ(2U, output.size());
-  output.clear();
-
-  // Although we have 3 foreign sessions, only 1 is valid/clean enough.
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(1U, foreign_sessions.size());
-  foreign_sessions.clear();
-
-  // Everything should get removed here.
-  manager()->DoGarbageCollection();
-  // Expect 5 deletions. tag1 header only, tag2 tab only, tag3 header + 2x tabs.
-  ASSERT_EQ(5U, output.size());
-  ASSERT_TRUE(AllOfChangesAreType(output, SyncChange::ACTION_DELETE));
-}
-
-// Test that an update to a previously considered "stale" session,
-// prior to garbage collection, will save the session from deletion.
-TEST_F(SessionsSyncManagerTest, GarbageCollectionHonoursUpdate) {
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession(kTag1, kTabIds1, &tabs1));
-  SyncDataList foreign_data;
-  base::Time tag1_time = base::Time::Now() - base::TimeDelta::FromDays(21);
-  foreign_data.push_back(CreateRemoteData(meta, tag1_time));
-  AddTabsToSyncDataList(tabs1, &foreign_data);
-  SyncChangeList output;
-  AddWindow();
-  InitWithSyncDataTakeOutput(foreign_data, &output);
-  ASSERT_EQ(2U, output.size());
-
-  // Update to a non-stale time.
-  sync_pb::EntitySpecifics update_entity;
-  update_entity.mutable_session()->CopyFrom(tabs1[0]);
-  SyncChangeList changes;
-  changes.push_back(SyncChange(FROM_HERE, SyncChange::ACTION_UPDATE,
-                               CreateRemoteData(tabs1[0], base::Time::Now())));
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-
-  // Check that the foreign session was associated and retrieve the data.
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(1U, foreign_sessions.size());
-  foreign_sessions.clear();
-
-  // Verify the now non-stale session does not get deleted.
-  manager()->DoGarbageCollection();
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(1U, foreign_sessions.size());
-  std::vector<std::vector<SessionID>> session_reference;
-  session_reference.push_back(kTabIds1);
-  helper()->VerifySyncedSession(kTag1, session_reference,
-                                *(foreign_sessions[0]));
-}
-
-// Test that NOTIFICATION_FOREIGN_SESSION_UPDATED is sent when processing
-// sync changes.
-TEST_F(SessionsSyncManagerTest, NotifiedOfUpdates) {
-  InitWithNoSyncData();
-
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession("tag1", SessionIDs({5}), &tabs1));
-
-  SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_ADD));
-  EXPECT_CALL(*mock_foreign_session_updated_cb(), Run());
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-
-  changes.clear();
-  AddTabsToChangeList(tabs1, SyncChange::ACTION_ADD, &changes);
-  EXPECT_CALL(*mock_foreign_session_updated_cb(), Run());
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-
-  changes.clear();
-  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_DELETE));
-  EXPECT_CALL(*mock_foreign_session_updated_cb(), Run());
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Test that NOTIFICATION_FOREIGN_SESSION_UPDATED is sent when handling
-// local hide/removal of foreign session.
-TEST_F(SessionsSyncManagerTest, NotifiedOfLocalRemovalOfForeignSession) {
-  InitWithNoSyncData();
-  const std::string tag("tag1");
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession(tag, SessionIDs({5}), &tabs1));
-
-  SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_ADD));
-  manager()->ProcessSyncChanges(FROM_HERE, changes);
-
-  EXPECT_CALL(*mock_foreign_session_updated_cb(), Run());
-  manager()->GetOpenTabsUIDelegate()->DeleteForeignSession(tag);
-}
-
-// Tests receipt of duplicate tab IDs in the same window.  This should never
-// happen, but we want to make sure the client won't do anything bad if it does
-// receive such garbage input data.
-TEST_F(SessionsSyncManagerTest, ReceiveDuplicateTabInSameWindow) {
-  std::string tag = "tag1";
-
-  // Reuse tab ID 10 in an attempt to trigger bad behavior.
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession(tag, kTabIds1, &tabs1));
-
-  // Set up initial data.
-  SyncDataList initial_data;
-  sync_pb::EntitySpecifics entity;
-  entity.mutable_session()->CopyFrom(meta);
-  initial_data.push_back(CreateRemoteData(entity));
-  AddTabsToSyncDataList(tabs1, &initial_data);
-
-  SyncChangeList output;
-  InitWithSyncDataTakeOutput(initial_data, &output);
-}
-
-// Tests receipt of duplicate tab IDs for the same session.  The duplicate tab
-// ID is present in two different windows.  A client can't be expected to do
-// anything reasonable with this input, but we can expect that it doesn't
-// crash.
-TEST_F(SessionsSyncManagerTest, ReceiveDuplicateTabInOtherWindow) {
-  // Tab ID 10 is a duplicate.
-  const std::vector<SessionID> tab_list1 = SessionIDs({5, 10, 15});
-  const std::vector<SessionID> tab_list2 = SessionIDs({7, 10, 17});
-
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession(kTag1, tab_list1, &tabs1));
-
-  // Add a second window.  Tab ID 10 is a duplicate.
-  helper()->AddWindowSpecifics(kWindowId2, tab_list2, &meta);
-
-  // Set up initial data.
-  SyncDataList initial_data;
-  sync_pb::EntitySpecifics entity;
-  entity.mutable_session()->CopyFrom(meta);
-  initial_data.push_back(CreateRemoteData(entity));
-  AddTabsToSyncDataList(tabs1, &initial_data);
-
-  for (SessionID tab_id : tab_list2) {
-    sync_pb::EntitySpecifics entity;
-    helper()->BuildTabSpecifics(kTag1, kWindowId1, tab_id,
-                                entity.mutable_session());
-    initial_data.push_back(CreateRemoteData(entity));
-  }
-
-  SyncChangeList output;
-  InitWithSyncDataTakeOutput(initial_data, &output);
-}
-
-// Tests receipt of multiple unassociated tabs and makes sure that
-// the ones with later timestamp win
-TEST_F(SessionsSyncManagerTest, ReceiveDuplicateUnassociatedTabs) {
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession(kTag1, kTabIds1, &tabs1));
-
-  // Set up initial data.
-  SyncDataList initial_data;
-  initial_data.push_back(CreateRemoteData(meta));
-
-  sync_pb::EntitySpecifics entity;
-
-  for (size_t i = 0; i < tabs1.size(); ++i) {
-    entity.mutable_session()->CopyFrom(tabs1[i]);
-    initial_data.push_back(
-        CreateRemoteData(entity, base::Time::FromDoubleT(2000)));
-  }
-
-  // Add two more tabs with duplicating IDs but with different modification
-  // times, one before and one after the tabs above.
-  // These two tabs get a different visual indices to distinguish them from the
-  // tabs above that get visual index 1 by default.
-  sync_pb::SessionSpecifics duplicating_tab1;
-  helper()->BuildTabSpecifics(kTag1, kWindowId1, kTabIds1[1],
-                              &duplicating_tab1);
-  duplicating_tab1.mutable_tab()->set_tab_visual_index(2);
-  entity.mutable_session()->CopyFrom(duplicating_tab1);
-  initial_data.push_back(
-      CreateRemoteData(entity, base::Time::FromDoubleT(1000)));
-
-  sync_pb::SessionSpecifics duplicating_tab2;
-  helper()->BuildTabSpecifics(kTag1, kWindowId1, kTabIds1[2],
-                              &duplicating_tab2);
-  duplicating_tab2.mutable_tab()->set_tab_visual_index(3);
-  entity.mutable_session()->CopyFrom(duplicating_tab2);
-  initial_data.push_back(
-      CreateRemoteData(entity, base::Time::FromDoubleT(3000)));
-
-  SyncChangeList output;
-  InitWithSyncDataTakeOutput(initial_data, &output);
-
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-
-  const std::vector<std::unique_ptr<sessions::SessionTab>>& window_tabs =
-      foreign_sessions[0]
-          ->windows.find(kWindowId1)
-          ->second->wrapped_window.tabs;
-  ASSERT_EQ(4U, window_tabs.size());
-  // The first one is from the original set of tabs.
-  ASSERT_EQ(1, window_tabs[0]->tab_visual_index);
-  // The one from the original set of tabs wins over duplicating_tab1.
-  ASSERT_EQ(1, window_tabs[1]->tab_visual_index);
-  // duplicating_tab2 wins due to the later timestamp.
-  ASSERT_EQ(3, window_tabs[2]->tab_visual_index);
-}
-
-// Verify that GetAllForeignSessions returns all sessions sorted by recency.
-TEST_F(SessionsSyncManagerTest, GetAllForeignSessions) {
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  sync_pb::SessionSpecifics meta1(
-      helper()->BuildForeignSession(kTag1, kTabIds1, &tabs1));
-
-  std::vector<sync_pb::SessionSpecifics> tabs2;
-  sync_pb::SessionSpecifics meta2(
-      helper()->BuildForeignSession(kTag2, kTabIds1, &tabs2));
-
-  SyncDataList initial_data;
-  initial_data.push_back(
-      CreateRemoteData(meta1, base::Time::FromInternalValue(10)));
-  AddTabsToSyncDataList(tabs1, &initial_data);
-  initial_data.push_back(
-      CreateRemoteData(meta2, base::Time::FromInternalValue(200)));
-  AddTabsToSyncDataList(tabs2, &initial_data);
-
-  SyncChangeList output;
-  InitWithSyncDataTakeOutput(initial_data, &output);
-
-  std::vector<const SyncedSession*> foreign_sessions;
-  ASSERT_TRUE(manager()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
-      &foreign_sessions));
-  ASSERT_EQ(2U, foreign_sessions.size());
-  ASSERT_GT(foreign_sessions[0]->modified_time,
-            foreign_sessions[1]->modified_time);
-}
-
-// Verify that GetForeignSessionTabs returns all tabs for a session sorted
-// by recency.
-TEST_F(SessionsSyncManagerTest, GetForeignSessionTabs) {
-  std::vector<sync_pb::SessionSpecifics> tabs1;
-  sync_pb::SessionSpecifics meta(
-      helper()->BuildForeignSession(kTag1, kTabIds1, &tabs1));
-  // Add a second window.
-  helper()->AddWindowSpecifics(kWindowId2, kTabIds2, &meta);
-
-  // Set up initial data.
-  SyncDataList initial_data;
-  initial_data.push_back(CreateRemoteData(meta));
-
-  // Add the first window's tabs.
-  AddTabsToSyncDataList(tabs1, &initial_data);
-
-  // Add the second window's tabs.
-  for (size_t i = 0; i < kTabIds2.size(); ++i) {
-    sync_pb::EntitySpecifics entity;
-    helper()->BuildTabSpecifics(kTag1, kWindowId1, kTabIds2[i],
-                                entity.mutable_session());
-    // Order the tabs oldest to most recent and left to right visually.
-    initial_data.push_back(
-        CreateRemoteData(entity, base::Time::FromInternalValue(i + 1)));
-  }
-
-  SyncChangeList output;
-  InitWithSyncDataTakeOutput(initial_data, &output);
-
-  std::vector<const sessions::SessionTab*> tabs;
-  ASSERT_TRUE(
-      manager()->GetOpenTabsUIDelegate()->GetForeignSessionTabs(kTag1, &tabs));
-  // Assert that the size matches the total number of tabs and that the order
-  // is from most recent to least.
-  ASSERT_EQ(kTabIds1.size() + kTabIds2.size(), tabs.size());
-  base::Time last_time;
-  for (size_t i = 0; i < tabs.size(); ++i) {
-    base::Time this_time = tabs[i]->timestamp;
-    if (i > 0)
-      ASSERT_GE(last_time, this_time);
-    last_time = tabs[i]->timestamp;
-  }
-}
-
-// Ensure model association associates the pre-existing tabs.
-TEST_F(SessionsSyncManagerTest, SwappedOutOnRestore) {
-  // Start with three tabs in a window.
-  TestSyncedWindowDelegate* window = AddWindow();
-  TestSyncedTabDelegate* tab1 = AddTab(window->GetSessionId(), kFoo1);
-  tab1->Navigate(kFoo2);
-  TestSyncedTabDelegate* tab2 = AddTab(window->GetSessionId(), kBar1);
-  tab2->Navigate(kBar2);
-
-  SyncDataList in;
-  SyncChangeList out;
-  InitWithSyncDataTakeOutput(in, &out);
-
-  // Should be one header add, 2 tab adds/updates, one header update.
-  ASSERT_EQ(4U, out.size());
-
-  // Now update the sync data to be:
-  // * one "normal" fully loaded tab
-  // * one placeholder tab with no WebContents and no tab_id change
-  sync_pb::EntitySpecifics t0_entity = out[1].sync_data().GetSpecifics();
-  sync_pb::EntitySpecifics t1_entity = out[2].sync_data().GetSpecifics();
-  in.push_back(CreateRemoteData(t0_entity));
-  in.push_back(CreateRemoteData(t1_entity));
-  out.clear();
-  manager()->StopSyncing(syncer::SESSIONS);
-  ResetWindows();
-
-  PlaceholderTabDelegate t1_override(
-      SessionID::FromSerializedValue(t1_entity.session().tab().tab_id()));
-  window = AddWindow();
-  window->OverrideTabAt(0, tab1);
-  window->OverrideTabAt(1, &t1_override);
-  InitWithSyncDataTakeOutput(in, &out);
-
-  // The last change should be the final header update, reflecting 1 window
-  // and 2 tabs.
-  VerifyLocalHeaderChange(out.back(), 1, 2);
-
-  // There should be one tab change, for the fully associated tab. The
-  // window-ID change for the placeholder tab is not reported to avoid traffic,
-  // since nothing relies on it.
-  ASSERT_TRUE(AllOfChangesAreType(*FilterOutLocalHeaderChanges(&out),
-                                  SyncChange::ACTION_UPDATE));
-  ASSERT_EQ(1U, out.size());
-  VerifyLocalTabChange(out[0], 2, kFoo2);
-}
-
-// Ensure model association does not update the window ID for placeholder tabs.
-TEST_F(SessionsSyncManagerTest, WindowIdNotUpdatedOnRestoreForPlaceholderTab) {
-  SyncDataList in;
-  SyncChangeList out;
-
-  // Set up one tab and start sync with it.
-  TestSyncedWindowDelegate* window = AddWindow();
-  AddTab(window->GetSessionId(), kFoo1);
-  InitWithSyncDataTakeOutput(in, &out);
-
-  // Should be one header add, 1 tab add, and one header update.
-  ASSERT_EQ(3U, out.size());
-  const sync_pb::EntitySpecifics t0_entity = out[1].sync_data().GetSpecifics();
-  ASSERT_TRUE(t0_entity.session().has_tab());
-
-  in.push_back(CreateRemoteData(t0_entity));
-  out.clear();
-  manager()->StopSyncing(syncer::SESSIONS);
-  ResetWindows();
-
-  // Override the tab with a placeholder tab delegate.
-  PlaceholderTabDelegate t0_override(
-      SessionID::FromSerializedValue(t0_entity.session().tab().tab_id()));
-
-  // Set up the window with the new window ID and placeholder tab.
-  window = AddWindow();
-  window->OverrideTabAt(0, &t0_override);
-  InitWithSyncDataTakeOutput(in, &out);
-
-  // There should be no change other than the header update.
-  ASSERT_EQ(0U, FilterOutLocalHeaderChanges(&out)->size());
-}
-
-// Ensure that the manager properly ignores a restored placeholder that refers
-// to a tab node that doesn't exist
-TEST_F(SessionsSyncManagerTest, RestoredPlacholderTabNodeDeleted) {
-  syncer::SyncDataList in;
-  syncer::SyncChangeList out;
-
-  // Set up one tab and start sync with it.
-  TestSyncedWindowDelegate* window = AddWindow();
-  AddTab(window->GetSessionId(), kFoo1);
-  InitWithSyncDataTakeOutput(in, &out);
-
-  // Should be one header add, 1 tab add, and one header update.
-  ASSERT_EQ(3U, out.size());
-  const sync_pb::EntitySpecifics t0_entity = out[1].sync_data().GetSpecifics();
-  ASSERT_TRUE(t0_entity.session().has_tab());
-
-  out.clear();
-  manager()->StopSyncing(syncer::SESSIONS);
-
-  // Override the tab with a placeholder tab delegate.
-  PlaceholderTabDelegate t0_override(
-      SessionID::FromSerializedValue(t0_entity.session().tab().tab_id()));
-
-  // Override the tab with a placeholder whose sync entity won't exist.
-  window->OverrideTabAt(0, &t0_override);
-  InitWithSyncDataTakeOutput(in, &out);
-
-  // Because no entities were passed in at associate time, there should be no
-  // tab changes.
-  ASSERT_EQ(0U, FilterOutLocalHeaderChanges(&out)->size());
-}
-
-// Tests that task ids are generated for navigations on local tabs.
-TEST_F(SessionsSyncManagerTest, TrackTasksOnLocalTabModified) {
-  SyncChangeList changes;
-  TestSyncedWindowDelegate* window = AddWindow();
-  InitWithSyncDataTakeOutput(SyncDataList(), &changes);
-  SessionID window_id = window->GetSessionId();
-  ASSERT_FALSE(manager()->current_machine_tag().empty());
-  changes.clear();
-
-  // Tab 1
-  AddTab(window_id, kFoo1)
-      ->Navigate(kFoo2, base::Time::Now(), ui::PAGE_TRANSITION_TYPED);
-  // Tab 2
-  AddTab(window_id, kBar1)
-      ->Navigate(kBar2, base::Time::Now(), ui::PAGE_TRANSITION_LINK);
-
-  // We only test changes for tab add and tab update, and ignore header updates.
-  FilterOutLocalHeaderChanges(&changes);
-  // Sync data of adding Tab 1 change
-  sync_pb::SessionTab tab =
-      SyncDataLocal(changes[0].sync_data()).GetSpecifics().session().tab();
-  EXPECT_EQ(tab.navigation_size(), 1);
-  EXPECT_EQ(tab.navigation(0).global_id(), tab.navigation(0).task_id());
-  EXPECT_TRUE(tab.navigation(0).ancestor_task_id().empty());
-
-  // Sync data of updating Tab 1 change
-  tab = SyncDataLocal(changes[1].sync_data()).GetSpecifics().session().tab();
-  EXPECT_EQ(tab.navigation_size(), 2);
-  // navigation(0) and navigation(1) are two separated tasks.
-  EXPECT_EQ(tab.navigation(0).global_id(), tab.navigation(0).task_id());
-  EXPECT_TRUE(tab.navigation(0).ancestor_task_id().empty());
-  EXPECT_EQ(tab.navigation(1).global_id(), tab.navigation(1).task_id());
-  EXPECT_TRUE(tab.navigation(1).ancestor_task_id().empty());
-
-  // Sync data of adding Tab 2 change
-  tab = SyncDataLocal(changes[2].sync_data()).GetSpecifics().session().tab();
-  EXPECT_EQ(tab.navigation_size(), 1);
-  EXPECT_EQ(tab.navigation(0).global_id(), tab.navigation(0).task_id());
-  EXPECT_TRUE(tab.navigation(0).ancestor_task_id().empty());
-
-  // Sync data of updating Tab 2 change
-  tab = SyncDataLocal(changes[3].sync_data()).GetSpecifics().session().tab();
-  EXPECT_EQ(tab.navigation_size(), 2);
-  EXPECT_EQ(tab.navigation(0).global_id(), tab.navigation(0).task_id());
-  EXPECT_TRUE(tab.navigation(0).ancestor_task_id().empty());
-  EXPECT_EQ(tab.navigation(1).global_id(), tab.navigation(1).task_id());
-  // navigation(1) is a subtask of navigation(0).
-  EXPECT_EQ(tab.navigation(1).ancestor_task_id_size(), 1);
-  EXPECT_EQ(tab.navigation(1).ancestor_task_id(0), tab.navigation(0).task_id());
-}
-
-}  // namespace sync_sessions
diff --git a/components/unified_consent/unified_consent_service.cc b/components/unified_consent/unified_consent_service.cc
index e4a76b5e..6e961b8 100644
--- a/components/unified_consent/unified_consent_service.cc
+++ b/components/unified_consent/unified_consent_service.cc
@@ -65,28 +65,10 @@
     syncer::SyncService* sync_service) {
   DCHECK(!scoped_sync_observer_.IsObservingSources());
 
-// Warning: ugly code ahead. See https://crbug.com/885382 for background.
-#if defined(OS_ANDROID) || defined(OS_IOS)
-  syncer::ModelTypeSet user_selectable_types_except_user_events(
-      syncer::AUTOFILL, syncer::BOOKMARKS, syncer::PASSWORDS,
-      syncer::PREFERENCES, syncer::PROXY_TABS,
-#if BUILDFLAG(ENABLE_READING_LIST)
-      syncer::READING_LIST,
-#endif
-      syncer::TYPED_URLS);
-#else
-  syncer::ModelTypeSet user_selectable_types_except_user_events =
-      syncer::UserSelectableTypes();
-  // USER_EVENTS data type doesn't have to be enabled, because it is not
-  // configurable if Unified Consent feature is disabled.
-  user_selectable_types_except_user_events.Remove(syncer::USER_EVENTS);
-#endif
-
   if (sync_service->GetUserSettings()->GetChosenDataTypes().HasAll(
-          user_selectable_types_except_user_events)) {
+          syncer::UserSelectableTypes())) {
     // As part of the migration of a profile to Unified Consent, sync everything
-    // is disabled but sync continues to be enabled for all data types except
-    // USER_EVENTS. Therefore it is desired to restore sync everything when
+    // is disabled. Therefore it is desired to restore sync everything when
     // rolling back unified consent to leave sync in the same state as the one
     // before migration.
     sync_service->GetUserSettings()->SetChosenDataTypes(
@@ -494,11 +476,10 @@
   pref_service_->SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
                             url_keyed_metrics_enabled);
 
-  // Disable the datatype user events for newly migrated users. Also set
-  // sync-everything to false, so it matches unified consent given.
+  // Set sync-everything to false, so it matches unified consent given.
   PostTaskToUpdateSyncSettings(
       /*sync_everything=*/false, /*enable_data_types=*/syncer::ModelTypeSet(),
-      /*disable_data_types=*/syncer::ModelTypeSet(syncer::USER_EVENTS));
+      /*disable_data_types=*/syncer::ModelTypeSet());
 
   SetMigrationState(MigrationState::kCompleted);
 }
@@ -534,12 +515,6 @@
         metrics::SettingsHistogramValue::kUnifiedConsentGiven);
     metric_recorded = true;
   }
-  if (identity_manager_->HasPrimaryAccount() &&
-      sync_service_->GetUserSettings()->GetChosenDataTypes().Has(
-          syncer::USER_EVENTS)) {
-    RecordSettingsHistogramSample(metrics::SettingsHistogramValue::kUserEvents);
-    metric_recorded = true;
-  }
   metric_recorded |= RecordSettingsHistogramFromPref(
       prefs::kUrlKeyedAnonymizedDataCollectionEnabled, pref_service_,
       metrics::SettingsHistogramValue::kUrlKeyedAnonymizedDataCollection);
@@ -562,12 +537,8 @@
     return;
   }
 
-  syncer::ModelTypeSet user_types_without_user_events =
-      syncer::UserSelectableTypes();
-  user_types_without_user_events.Remove(syncer::USER_EVENTS);
-
   if (!sync_service_->GetUserSettings()->GetChosenDataTypes().HasAll(
-          user_types_without_user_events)) {
+          syncer::UserSelectableTypes())) {
     RecordConsentBumpSuppressReason(
         metrics::ConsentBumpSuppressReason::kUserTurnedSyncDatatypeOff);
   } else if (!AreAllOnByDefaultPrivacySettingsOn()) {
diff --git a/components/unified_consent/unified_consent_service_unittest.cc b/components/unified_consent/unified_consent_service_unittest.cc
index 9d42cde..a0ebca0 100644
--- a/components/unified_consent/unified_consent_service_unittest.cc
+++ b/components/unified_consent/unified_consent_service_unittest.cc
@@ -469,17 +469,14 @@
   syncer::SyncPrefs sync_prefs(&pref_service_);
   EXPECT_TRUE(sync_service_.GetUserSettings()->IsSyncEverythingEnabled());
   EXPECT_TRUE(sync_service_.IsSyncFeatureActive());
-  EXPECT_TRUE(sync_service_.GetPreferredDataTypes().Has(syncer::USER_EVENTS));
   // Url keyed data collection is off before the migration.
   EXPECT_FALSE(pref_service_.GetBoolean(
       prefs::kUrlKeyedAnonymizedDataCollectionEnabled));
 
   CreateConsentService();
   EXPECT_EQ(GetMigrationState(), unified_consent::MigrationState::kCompleted);
-  // During the migration USER_EVENTS is disabled and Url keyed data collection
-  // is enabled.
+  // During the migration Url keyed data collection is enabled.
   EXPECT_FALSE(sync_service_.GetUserSettings()->IsSyncEverythingEnabled());
-  EXPECT_FALSE(sync_service_.GetPreferredDataTypes().Has(syncer::USER_EVENTS));
   EXPECT_TRUE(pref_service_.GetBoolean(
       prefs::kUrlKeyedAnonymizedDataCollectionEnabled));
 }
@@ -693,9 +690,6 @@
       metrics::SettingsHistogramValue::kUnifiedConsentGiven, 1);
   histogram_tester.ExpectBucketCount(
       "UnifiedConsent.SyncAndGoogleServicesSettings",
-      metrics::SettingsHistogramValue::kUserEvents, 1);
-  histogram_tester.ExpectBucketCount(
-      "UnifiedConsent.SyncAndGoogleServicesSettings",
       metrics::SettingsHistogramValue::kUrlKeyedAnonymizedDataCollection, 1);
   histogram_tester.ExpectBucketCount(
       "UnifiedConsent.SyncAndGoogleServicesSettings",
@@ -704,7 +698,7 @@
       "UnifiedConsent.SyncAndGoogleServicesSettings",
       metrics::SettingsHistogramValue::kSpellCheck, 1);
   histogram_tester.ExpectTotalCount(
-      "UnifiedConsent.SyncAndGoogleServicesSettings", 5);
+      "UnifiedConsent.SyncAndGoogleServicesSettings", 4);
 }
 
 TEST_F(UnifiedConsentServiceTest, SettingsHistogram_NoUnifiedConsentGiven) {
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy.cc b/content/browser/background_fetch/background_fetch_delegate_proxy.cc
index a4cb7b0..3f1ec4c 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy.cc
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy.cc
@@ -156,9 +156,12 @@
       headers.SetHeader("Origin", origin.Serialize());
     }
 
+    // TODO(crbug.com/774054): Update |has_request_body| after the cache storage
+    // supports request bodies.
     delegate_->DownloadUrl(job_unique_id, request->download_guid(),
                            fetch_request.method, fetch_request.url,
-                           traffic_annotation, headers);
+                           traffic_annotation, headers,
+                           /* has_request_body= */ false);
   }
 
   void Abort(const std::string& job_unique_id) {
@@ -201,6 +204,10 @@
       std::unique_ptr<content::BackgroundFetchResponse> response) override;
   void OnUIActivated(const std::string& unique_id) override;
   void OnDelegateShutdown() override;
+  void GetUploadData(
+      const std::string& job_unique_id,
+      const std::string& download_guid,
+      BackgroundFetchDelegate::GetUploadDataCallback callback) override;
 
  private:
   // Weak reference to the IO thread outer class that owns us.
@@ -273,6 +280,31 @@
   delegate_ = nullptr;
 }
 
+void BackgroundFetchDelegateProxy::Core::GetUploadData(
+    const std::string& job_unique_id,
+    const std::string& download_guid,
+    BackgroundFetchDelegate::GetUploadDataCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  // Pass this to the IO thread for processing, but wrap |callback|
+  // to be posted back to the UI thread when executed.
+  BackgroundFetchDelegate::GetUploadDataCallback wrapped_callback =
+      base::BindOnce(
+          [](BackgroundFetchDelegate::GetUploadDataCallback callback,
+             scoped_refptr<network::ResourceRequestBody> body) {
+            base::PostTaskWithTraits(
+                FROM_HERE, {BrowserThread::UI},
+                base::BindOnce(std::move(callback), std::move(body)));
+          },
+          std::move(callback));
+
+  base::PostTaskWithTraits(
+      FROM_HERE, {BrowserThread::IO},
+      base::BindOnce(&BackgroundFetchDelegateProxy::GetUploadData, io_parent_,
+                     job_unique_id, download_guid,
+                     std::move(wrapped_callback)));
+}
+
 BackgroundFetchDelegateProxy::JobDetails::JobDetails(
     base::WeakPtr<Controller> controller,
     std::vector<scoped_refptr<BackgroundFetchRequestInfo>>
@@ -495,4 +527,17 @@
     job_details.controller->DidCompleteRequest(request_info);
 }
 
+void BackgroundFetchDelegateProxy::GetUploadData(
+    const std::string& job_unique_id,
+    const std::string& download_guid,
+    BackgroundFetchDelegate::GetUploadDataCallback callback) {
+  auto& job_details = job_details_map_.find(job_unique_id)->second;
+  DCHECK(job_details.controller);
+
+  const auto& request =
+      job_details.current_request_map[download_guid]->fetch_request_ptr();
+  job_details.controller->GetUploadData(
+      BackgroundFetchSettledFetch::CloneRequest(request), std::move(callback));
+}
+
 }  // namespace content
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy.h b/content/browser/background_fetch/background_fetch_delegate_proxy.h
index 6b266b2..2cdd7fe 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy.h
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy.h
@@ -52,6 +52,12 @@
     virtual void AbortFromDelegate(
         blink::mojom::BackgroundFetchFailureReason) = 0;
 
+    // Called by the delegate when the Download Service is requesting the
+    // upload data.
+    virtual void GetUploadData(
+        blink::mojom::FetchAPIRequestPtr request,
+        BackgroundFetchDelegate::GetUploadDataCallback callback) = 0;
+
     virtual ~Controller() {}
   };
 
@@ -143,6 +149,11 @@
   // Should only be called from the BackgroundFetchDelegate (on the IO thread).
   void DidActivateUI(const std::string& job_unique_id);
 
+  // Should only be called from the BackgroundFetchDelegate (on the IO thread).
+  void GetUploadData(const std::string& job_unique_id,
+                     const std::string& download_guid,
+                     BackgroundFetchDelegate::GetUploadDataCallback callback);
+
   std::unique_ptr<Core, BrowserThread::DeleteOnUIThread> ui_core_;
   base::WeakPtr<Core> ui_core_ptr_;
 
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc b/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
index 688e14c..ddfe7db 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
@@ -49,7 +49,8 @@
                    const std::string& method,
                    const GURL& url,
                    const net::NetworkTrafficAnnotationTag& traffic_annotation,
-                   const net::HttpRequestHeaders& headers) override {
+                   const net::HttpRequestHeaders& headers,
+                   bool has_request_body) override {
     if (!client())
       return;
 
@@ -135,6 +136,10 @@
   void AbortFromDelegate(
       blink::mojom::BackgroundFetchFailureReason reason_to_abort) override {}
 
+  void GetUploadData(
+      blink::mojom::FetchAPIRequestPtr request,
+      BackgroundFetchDelegate::GetUploadDataCallback callback) override {}
+
   bool request_started_ = false;
   bool request_completed_ = false;
   base::WeakPtrFactory<FakeController> weak_ptr_factory_;
diff --git a/content/browser/background_fetch/background_fetch_job_controller.cc b/content/browser/background_fetch/background_fetch_job_controller.cc
index 8987da8..c102701 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.cc
+++ b/content/browser/background_fetch/background_fetch_job_controller.cc
@@ -4,8 +4,10 @@
 
 #include "content/browser/background_fetch/background_fetch_job_controller.h"
 #include "content/browser/background_fetch/background_fetch_data_manager.h"
+#include "content/browser/background_fetch/background_fetch_request_match_params.h"
 #include "content/public/common/origin_util.h"
 #include "services/network/public/cpp/cors/cors.h"
+#include "services/network/public/cpp/resource_request_body.h"
 #include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom.h"
 
 #include <utility>
@@ -295,4 +297,39 @@
   Finish(BackgroundFetchFailureReason::NONE, base::DoNothing());
 }
 
+void BackgroundFetchJobController::GetUploadData(
+    blink::mojom::FetchAPIRequestPtr request,
+    BackgroundFetchDelegate::GetUploadDataCallback callback) {
+  data_manager_->MatchRequests(
+      registration_id(),
+      std::make_unique<BackgroundFetchRequestMatchParams>(
+          std::move(request), /* match_params= */ nullptr,
+          /* match_all= */ false),
+      base::BindOnce(&BackgroundFetchJobController::DidGetUploadData,
+                     GetWeakPtr(), std::move(callback)));
+}
+
+void BackgroundFetchJobController::DidGetUploadData(
+    BackgroundFetchDelegate::GetUploadDataCallback callback,
+    BackgroundFetchError error,
+    std::vector<BackgroundFetchSettledFetch> fetches) {
+  if (error != BackgroundFetchError::NONE) {
+    Abort(BackgroundFetchFailureReason::SERVICE_WORKER_UNAVAILABLE,
+          base::DoNothing());
+    std::move(callback).Run(/* request_body= */ nullptr);
+    return;
+  }
+
+  DCHECK_EQ(fetches.size(), 1u);
+  DCHECK(fetches[0].request->blob);
+
+  network::mojom::DataPipeGetterPtr data_pipe_getter_ptr;
+  blink::mojom::BlobPtr blob_ptr(std::move(fetches[0].request->blob->blob));
+  blob_ptr->AsDataPipeGetter(MakeRequest(&data_pipe_getter_ptr));
+
+  auto request_body = base::MakeRefCounted<network::ResourceRequestBody>();
+  request_body->AppendDataPipe(std::move(data_pipe_getter_ptr));
+  std::move(callback).Run(std::move(request_body));
+}
+
 }  // namespace content
diff --git a/content/browser/background_fetch/background_fetch_job_controller.h b/content/browser/background_fetch/background_fetch_job_controller.h
index 84cd80c..e48e6f2 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.h
+++ b/content/browser/background_fetch/background_fetch_job_controller.h
@@ -109,6 +109,9 @@
       const scoped_refptr<BackgroundFetchRequestInfo>& request) override;
   void AbortFromDelegate(
       blink::mojom::BackgroundFetchFailureReason failure_reason) override;
+  void GetUploadData(
+      blink::mojom::FetchAPIRequestPtr request,
+      BackgroundFetchDelegate::GetUploadDataCallback callback) override;
 
   // Aborts the fetch. |callback| will run with the result of marking the
   // registration for deletion.
@@ -137,6 +140,10 @@
   void Finish(blink::mojom::BackgroundFetchFailureReason reason_to_abort,
               ErrorCallback callback);
 
+  void DidGetUploadData(BackgroundFetchDelegate::GetUploadDataCallback callback,
+                        blink::mojom::BackgroundFetchError error,
+                        std::vector<BackgroundFetchSettledFetch> fetches);
+
   // Manager for interacting with the DB. It is owned by the
   // BackgroundFetchContext.
   BackgroundFetchDataManager* data_manager_;
diff --git a/content/browser/background_fetch/background_fetch_request_info.h b/content/browser/background_fetch/background_fetch_request_info.h
index 36c25f0..2ddeeced 100644
--- a/content/browser/background_fetch/background_fetch_request_info.h
+++ b/content/browser/background_fetch/background_fetch_request_info.h
@@ -68,6 +68,12 @@
     return *fetch_request_;
   }
 
+  // Returns the Fetch API Request Ptr object that details the developer's
+  // request.
+  const blink::mojom::FetchAPIRequestPtr& fetch_request_ptr() const {
+    return fetch_request_;
+  }
+
   // Returns the response code for the download. Available for both successful
   // and failed requests.
   int GetResponseCode() const;
diff --git a/content/browser/background_fetch/mock_background_fetch_delegate.cc b/content/browser/background_fetch/mock_background_fetch_delegate.cc
index 951fc00..e4fb322 100644
--- a/content/browser/background_fetch/mock_background_fetch_delegate.cc
+++ b/content/browser/background_fetch/mock_background_fetch_delegate.cc
@@ -85,7 +85,8 @@
     const std::string& method,
     const GURL& url,
     const net::NetworkTrafficAnnotationTag& traffic_annotation,
-    const net::HttpRequestHeaders& headers) {
+    const net::HttpRequestHeaders& headers,
+    bool has_request_body) {
   // TODO(delphick): Currently we just disallow re-using GUIDs but later when we
   // use the DownloadService, we should signal StartResult::UNEXPECTED_GUID.
   DCHECK(seen_guids_.find(guid) == seen_guids_.end());
diff --git a/content/browser/background_fetch/mock_background_fetch_delegate.h b/content/browser/background_fetch/mock_background_fetch_delegate.h
index b4d5fc6..9f67cf5 100644
--- a/content/browser/background_fetch/mock_background_fetch_delegate.h
+++ b/content/browser/background_fetch/mock_background_fetch_delegate.h
@@ -81,7 +81,8 @@
                    const std::string& method,
                    const GURL& url,
                    const net::NetworkTrafficAnnotationTag& traffic_annotation,
-                   const net::HttpRequestHeaders& headers) override;
+                   const net::HttpRequestHeaders& headers,
+                   bool has_request_body) override;
   void Abort(const std::string& job_unique_id) override;
   void MarkJobComplete(const std::string& job_unique_id) override;
   void UpdateUI(const std::string& job_unique_id,
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.cc b/content/browser/dom_storage/dom_storage_context_wrapper.cc
index 97064fc..64eff38 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.cc
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.cc
@@ -271,7 +271,8 @@
 }
 
 void DOMStorageContextWrapper::DeleteSessionStorage(
-    const SessionStorageUsageInfo& usage_info) {
+    const SessionStorageUsageInfo& usage_info,
+    base::OnceClosure callback) {
   if (mojo_session_state_) {
     // base::Unretained is safe here, because the mojo_session_state_ won't be
     // deleted until a ShutdownAndDelete task has been ran on the
@@ -279,10 +280,11 @@
     // mojo_session_state_ is set to null, preventing further tasks from being
     // queued.
     mojo_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&SessionStorageContextMojo::DeleteStorage,
-                                  base::Unretained(mojo_session_state_),
-                                  url::Origin::Create(usage_info.origin),
-                                  usage_info.namespace_id));
+        FROM_HERE,
+        base::BindOnce(&SessionStorageContextMojo::DeleteStorage,
+                       base::Unretained(mojo_session_state_),
+                       url::Origin::Create(usage_info.origin),
+                       usage_info.namespace_id, std::move(callback)));
     return;
   }
   DCHECK(context_.get());
@@ -290,6 +292,26 @@
       FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
       base::BindOnce(&DOMStorageContextImpl::DeleteSessionStorage, context_,
                      usage_info));
+  std::move(callback).Run();
+}
+
+void DOMStorageContextWrapper::PerformSessionStorageCleanup(
+    base::OnceClosure callback) {
+  DCHECK(context_.get());
+  DCHECK(callback);
+  if (mojo_session_state_) {
+    // base::Unretained is safe here, because the mojo_session_state_ won't be
+    // deleted until a ShutdownAndDelete task has been ran on the
+    // mojo_task_runner_, and as soon as that task is posted,
+    // mojo_session_state_ is set to null, preventing further tasks from being
+    // queued.
+    mojo_task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&SessionStorageContextMojo::PerformCleanup,
+                                  base::Unretained(mojo_session_state_),
+                                  std::move(callback)));
+    return;
+  }
+  std::move(callback).Run();
 }
 
 void DOMStorageContextWrapper::SetSaveSessionStorageOnDisk() {
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.h b/content/browser/dom_storage/dom_storage_context_wrapper.h
index 2de1e51..a66cf7e 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.h
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.h
@@ -61,7 +61,9 @@
   void DeleteLocalStorage(const GURL& origin,
                           base::OnceClosure callback) override;
   void PerformLocalStorageCleanup(base::OnceClosure callback) override;
-  void DeleteSessionStorage(const SessionStorageUsageInfo& usage_info) override;
+  void DeleteSessionStorage(const SessionStorageUsageInfo& usage_info,
+                            base::OnceClosure callback) override;
+  void PerformSessionStorageCleanup(base::OnceClosure callback) override;
   void SetSaveSessionStorageOnDisk() override;
   scoped_refptr<SessionStorageNamespace> RecreateSessionStorage(
       const std::string& namespace_id) override;
diff --git a/content/browser/dom_storage/session_storage_context_mojo.cc b/content/browser/dom_storage/session_storage_context_mojo.cc
index b9f0587..dc2efbe 100644
--- a/content/browser/dom_storage/session_storage_context_mojo.cc
+++ b/content/browser/dom_storage/session_storage_context_mojo.cc
@@ -89,6 +89,11 @@
       break;
   }
 }
+
+void SessionStorageErrorResponse(base::OnceClosure callback,
+                                 leveldb::mojom::DatabaseError error) {
+  std::move(callback).Run();
+}
 }  // namespace
 
 SessionStorageContextMojo::SessionStorageContextMojo(
@@ -253,26 +258,49 @@
 }
 
 void SessionStorageContextMojo::DeleteStorage(const url::Origin& origin,
-                                              const std::string& namespace_id) {
+                                              const std::string& namespace_id,
+                                              base::OnceClosure callback) {
   if (connection_state_ != CONNECTION_FINISHED) {
     RunWhenConnected(base::BindOnce(&SessionStorageContextMojo::DeleteStorage,
                                     weak_ptr_factory_.GetWeakPtr(), origin,
-                                    namespace_id));
+                                    namespace_id, std::move(callback)));
     return;
   }
   auto found = namespaces_.find(namespace_id);
   if (found != namespaces_.end() &&
       (found->second->IsPopulated() ||
        found->second->waiting_on_clone_population())) {
-    found->second->RemoveOriginData(origin);
+    found->second->RemoveOriginData(origin, std::move(callback));
   } else {
     // If we don't have the namespace loaded, then we can delete it all
     // using the metadata.
     std::vector<leveldb::mojom::BatchedOperationPtr> delete_operations;
     metadata_.DeleteArea(namespace_id, origin, &delete_operations);
-    database_->Write(std::move(delete_operations),
-                     base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
-                                    base::Unretained(this)));
+    if (database_) {
+      database_->Write(
+          std::move(delete_operations),
+          base::BindOnce(&SessionStorageContextMojo::OnCommitResultWithCallback,
+                         base::Unretained(this), std::move(callback)));
+    } else {
+      std::move(callback).Run();
+    }
+  }
+}
+
+void SessionStorageContextMojo::PerformCleanup(base::OnceClosure callback) {
+  if (connection_state_ != CONNECTION_FINISHED) {
+    RunWhenConnected(base::BindOnce(&SessionStorageContextMojo::PerformCleanup,
+                                    weak_ptr_factory_.GetWeakPtr(),
+                                    std::move(callback)));
+    return;
+  }
+  if (database_) {
+    for (const auto& it : data_maps_)
+      it.second->storage_area()->ScheduleImmediateCommit();
+    database_->RewriteDB(
+        base::BindOnce(&SessionStorageErrorResponse, std::move(callback)));
+  } else {
+    std::move(callback).Run();
   }
 }
 
@@ -466,9 +494,11 @@
   scoped_refptr<SessionStorageMetadata::MapData> map_entry =
       metadata_.RegisterNewMap(namespace_entry, origin, &save_operations);
 
-  database_->Write(std::move(save_operations),
-                   base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
-                                  base::Unretained(this)));
+  if (database_) {
+    database_->Write(std::move(save_operations),
+                     base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
+                                    base::Unretained(this)));
+  }
   return map_entry;
 }
 
@@ -514,6 +544,13 @@
   }
 }
 
+void SessionStorageContextMojo::OnCommitResultWithCallback(
+    base::OnceClosure callback,
+    leveldb::mojom::DatabaseError error) {
+  OnCommitResult(error);
+  std::move(callback).Run();
+}
+
 scoped_refptr<SessionStorageDataMap>
 SessionStorageContextMojo::MaybeGetExistingDataMapForId(
     const std::vector<uint8_t>& map_number_as_bytes) {
@@ -543,9 +580,11 @@
   auto namespace_entry = metadata_.GetOrCreateNamespaceEntry(new_namespace_id);
   metadata_.RegisterShallowClonedNamespace(source_namespace_entry,
                                            namespace_entry, &save_operations);
-  database_->Write(std::move(save_operations),
-                   base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
-                                  base::Unretained(this)));
+  if (database_) {
+    database_->Write(std::move(save_operations),
+                     base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
+                                    base::Unretained(this)));
+  }
 
   if (found) {
     it->second->PopulateAsClone(database_.get(), namespace_entry,
@@ -577,9 +616,11 @@
   DCHECK_EQ(connection_state_, CONNECTION_FINISHED);
   std::vector<leveldb::mojom::BatchedOperationPtr> delete_operations;
   metadata_.DeleteNamespace(namespace_id, &delete_operations);
-  database_->Write(std::move(delete_operations),
-                   base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
-                                  base::Unretained(this)));
+  if (database_) {
+    database_->Write(std::move(delete_operations),
+                     base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
+                                    base::Unretained(this)));
+  }
 }
 
 void SessionStorageContextMojo::RunWhenConnected(base::OnceClosure callback) {
@@ -673,6 +714,19 @@
                      weak_ptr_factory_.GetWeakPtr(), false));
 }
 
+void SessionStorageContextMojo::OnMojoConnectionDestroyed() {
+  UMA_HISTOGRAM_BOOLEAN("SessionStorageContext.OnConnectionDestroyed", true);
+  LOG(ERROR) << "Lost connection to database";
+  for (const auto& it : data_maps_)
+    it.second->storage_area()->CancelAllPendingRequests();
+
+  for (const auto& namespace_pair : namespaces_)
+    namespace_pair.second->Reset();
+
+  DCHECK(data_maps_.empty());
+  database_.reset();
+}
+
 void SessionStorageContextMojo::OnDatabaseOpened(
     bool in_memory,
     leveldb::mojom::DatabaseError status) {
@@ -700,6 +754,9 @@
 
   // Verify DB schema version.
   if (database_) {
+    database_.set_connection_error_handler(
+        base::BindOnce(&SessionStorageContextMojo::OnMojoConnectionDestroyed,
+                       weak_ptr_factory_.GetWeakPtr()));
     database_->Get(
         std::vector<uint8_t>(
             SessionStorageMetadata::kDatabaseVersionBytes,
diff --git a/content/browser/dom_storage/session_storage_context_mojo.h b/content/browser/dom_storage/session_storage_context_mojo.h
index 3cf456d..5a2d7d5 100644
--- a/content/browser/dom_storage/session_storage_context_mojo.h
+++ b/content/browser/dom_storage/session_storage_context_mojo.h
@@ -100,7 +100,11 @@
   void GetStorageUsage(GetStorageUsageCallback callback);
 
   void DeleteStorage(const url::Origin& origin,
-                     const std::string& namespace_id);
+                     const std::string& namespace_id,
+                     base::OnceClosure callback);
+
+  // Ensure that no traces of data are left in the backing storage.
+  void PerformCleanup(base::OnceClosure callback);
 
   // Called when the owning BrowserContext is ending. Schedules the commit of
   // any unsaved changes then deletes this object. All data on disk (where there
@@ -154,6 +158,8 @@
                          SessionStorageDataMap* map) override;
   void OnDataMapDestruction(const std::vector<uint8_t>& map_prefix) override;
   void OnCommitResult(leveldb::mojom::DatabaseError error) override;
+  void OnCommitResultWithCallback(base::OnceClosure callback,
+                                  leveldb::mojom::DatabaseError error);
 
   // SessionStorageNamespaceImplMojo::Delegate implementation:
   scoped_refptr<SessionStorageDataMap> MaybeGetExistingDataMapForId(
@@ -192,6 +198,7 @@
   void DeleteAndRecreateDatabase(const char* histogram_name);
   void OnDBDestroyed(bool recreate_in_memory,
                      leveldb::mojom::DatabaseError status);
+  void OnMojoConnectionDestroyed();
 
   void OnGotMetaData(GetStorageUsageCallback callback,
                      leveldb::mojom::DatabaseError status,
diff --git a/content/browser/dom_storage/session_storage_context_mojo_unittest.cc b/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
index 0a26f76..c883b73 100644
--- a/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
+++ b/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
@@ -908,6 +908,78 @@
   loop.Run();
 }
 
+// Tests that a SessionStorageContext still works if the database is
+// disconnected.
+TEST_F(SessionStorageContextMojoTest, MojoConnectionDisconnects) {
+  std::string namespace_id = base::GenerateGUID();
+  url::Origin origin = url::Origin::Create(GURL("http://foobar.com"));
+  auto key = StdStringToUint8Vector("key");
+  auto value = StdStringToUint8Vector("value");
+
+  std::map<std::vector<uint8_t>, std::vector<uint8_t>> test_data;
+  FakeLevelDBDatabase db(&test_data);
+  mojo::AssociatedBinding<leveldb::mojom::LevelDBDatabase> db_binding(&db);
+  leveldb::mojom::LevelDBDatabaseAssociatedPtr database_ptr;
+  leveldb::mojom::LevelDBDatabaseAssociatedRequest request =
+      MakeRequestAssociatedWithDedicatedPipe(&database_ptr);
+  context()->SetDatabaseForTesting(std::move(database_ptr));
+  db_binding.Bind(std::move(request));
+
+  // Put some data.
+  context()->CreateSessionNamespace(namespace_id);
+  blink::mojom::SessionStorageNamespacePtr ss_namespace;
+  context()->OpenSessionStorage(kTestProcessId, namespace_id,
+                                GetBadMessageCallback(),
+                                mojo::MakeRequest(&ss_namespace));
+  blink::mojom::StorageAreaAssociatedPtr area;
+  ss_namespace->OpenArea(origin, mojo::MakeRequest(&area));
+  EXPECT_TRUE(test::PutSync(area.get(), key, value, base::nullopt, "source"));
+  std::vector<uint8_t> result;
+
+  std::vector<blink::mojom::KeyValuePtr> data;
+  ASSERT_TRUE(test::GetAllSync(area.get(), &data));
+  EXPECT_EQ(1ul, data.size());
+
+  // Close the database connection.
+  db_binding.Close();
+  base::RunLoop().RunUntilIdle();
+
+  context()->CreateSessionNamespace(namespace_id);
+  context()->OpenSessionStorage(kTestProcessId, namespace_id,
+                                GetBadMessageCallback(),
+                                mojo::MakeRequest(&ss_namespace));
+  ss_namespace->OpenArea(origin, mojo::MakeRequest(&area));
+
+  // We can't access the data anymore.
+  ASSERT_TRUE(test::GetAllSync(area.get(), &data));
+  EXPECT_EQ(0ul, data.size());
+
+  // Check that session storage still works without a database.
+  EXPECT_TRUE(test::PutSync(area.get(), key, value, base::nullopt, "source"));
+  ASSERT_TRUE(test::GetAllSync(area.get(), &data));
+  EXPECT_EQ(1ul, data.size());
+
+  context()->DeleteStorage(origin, namespace_id, base::DoNothing());
+  ASSERT_TRUE(test::GetAllSync(area.get(), &data));
+  EXPECT_EQ(0ul, data.size());
+
+  EXPECT_TRUE(test::PutSync(area.get(), key, value, base::nullopt, "source"));
+  ASSERT_TRUE(test::GetAllSync(area.get(), &data));
+  EXPECT_EQ(1ul, data.size());
+  context()->DeleteSessionNamespace(namespace_id, true);
+  context()->ScavengeUnusedNamespaces(base::DoNothing());
+  ShutdownContext();
+
+  context()->CreateSessionNamespace(namespace_id);
+  context()->OpenSessionStorage(kTestProcessId, namespace_id,
+                                GetBadMessageCallback(),
+                                mojo::MakeRequest(&ss_namespace));
+  ss_namespace->OpenArea(origin, mojo::MakeRequest(&area));
+
+  ASSERT_TRUE(test::GetAllSync(area.get(), &data));
+  EXPECT_EQ(0ul, data.size());
+}
+
 TEST_F(SessionStorageContextMojoTest, DeleteStorage) {
   std::string namespace_id1 = base::GenerateGUID();
   url::Origin origin1 = url::Origin::Create(GURL("http://foobar.com"));
@@ -926,7 +998,7 @@
       leveldb_n1_o1.get(), leveldb::StringPieceToUint8Vector("key1"),
       leveldb::StringPieceToUint8Vector("value1"), base::nullopt, "source1"));
 
-  context()->DeleteStorage(origin1, namespace_id1);
+  context()->DeleteStorage(origin1, namespace_id1, base::DoNothing());
 
   std::vector<blink::mojom::KeyValuePtr> data;
   ASSERT_TRUE(test::GetAllSync(leveldb_n1_o1.get(), &data));
@@ -943,7 +1015,7 @@
   ShutdownContext();
 
   // This restarts the context, then deletes the storage.
-  context()->DeleteStorage(origin1, namespace_id1);
+  context()->DeleteStorage(origin1, namespace_id1, base::DoNothing());
 
   context()->CreateSessionNamespace(namespace_id1);
   context()->OpenSessionStorage(kTestProcessId, namespace_id1,
diff --git a/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc b/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc
index 136cf48e..e3244cf 100644
--- a/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc
+++ b/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc
@@ -13,6 +13,12 @@
 
 namespace content {
 
+namespace {
+void SessionStorageResponse(base::OnceClosure callback, bool success) {
+  std::move(callback).Run();
+}
+}  // namespace
+
 SessionStorageNamespaceImplMojo::SessionStorageNamespaceImplMojo(
     std::string namespace_id,
     SessionStorageDataMap::Listener* data_map_listener,
@@ -111,11 +117,12 @@
 }
 
 void SessionStorageNamespaceImplMojo::RemoveOriginData(
-    const url::Origin& origin) {
+    const url::Origin& origin,
+    base::OnceClosure callback) {
   if (waiting_on_clone_population_) {
     run_after_clone_population_.push_back(
         base::BindOnce(&SessionStorageNamespaceImplMojo::RemoveOriginData,
-                       base::Unretained(this), origin));
+                       base::Unretained(this), origin, std::move(callback)));
     return;
   }
   DCHECK(IsPopulated());
@@ -124,7 +131,8 @@
     return;
   // Renderer process expects |source| to always be two newline separated
   // strings.
-  it->second->DeleteAll("\n", base::DoNothing());
+  it->second->DeleteAll(
+      "\n", base::BindOnce(&SessionStorageResponse, std::move(callback)));
   it->second->NotifyObserversAllDeleted();
   it->second->data_map()->storage_area()->ScheduleImmediateCommit();
 }
diff --git a/content/browser/dom_storage/session_storage_namespace_impl_mojo.h b/content/browser/dom_storage/session_storage_namespace_impl_mojo.h
index 0951c9b7..de5b9c1 100644
--- a/content/browser/dom_storage/session_storage_namespace_impl_mojo.h
+++ b/content/browser/dom_storage/session_storage_namespace_impl_mojo.h
@@ -133,7 +133,7 @@
   // Removes data for the given origin from this namespace. If there is no data
   // map for that given origin, this does nothing. Expects that this namespace
   // is either populated or waiting for clone population.
-  void RemoveOriginData(const url::Origin& origin);
+  void RemoveOriginData(const url::Origin& origin, base::OnceClosure callback);
 
   // SessionStorageNamespace:
   // Connects the given database mojo request to the data map for the given
diff --git a/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc b/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc
index fb9e5c43..02516f9 100644
--- a/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc
+++ b/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc
@@ -394,7 +394,7 @@
       .WillOnce(base::test::RunClosure(loop.QuitClosure()));
 
   EXPECT_CALL(listener_, OnCommitResult(DatabaseError::OK)).Times(1);
-  namespace_impl->RemoveOriginData(test_origin1_);
+  namespace_impl->RemoveOriginData(test_origin1_, base::DoNothing());
 
   std::vector<blink::mojom::KeyValuePtr> data;
   EXPECT_TRUE(test::GetAllSync(leveldb_1.get(), &data));
@@ -422,7 +422,7 @@
   base::RunLoop loop;
   EXPECT_CALL(listener_, OnCommitResult(DatabaseError::OK))
       .WillOnce(base::test::RunClosure(loop.QuitClosure()));
-  namespace_impl->RemoveOriginData(test_origin1_);
+  namespace_impl->RemoveOriginData(test_origin1_, base::DoNothing());
   loop.Run();
 
   EXPECT_CALL(listener_, OnDataMapDestruction(StdStringToUint8Vector("0")))
diff --git a/content/browser/file_url_loader_factory.cc b/content/browser/file_url_loader_factory.cc
index 1bd35c6..3dd6f1d 100644
--- a/content/browser/file_url_loader_factory.cc
+++ b/content/browser/file_url_loader_factory.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -40,6 +41,7 @@
 #include "net/http/http_util.h"
 #include "net/url_request/redirect_info.h"
 #include "services/network/public/cpp/cors/cors_error_status.h"
+#include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/mojom/cors.mojom-shared.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
@@ -102,6 +104,12 @@
     return false;
   }
 
+  // Currently the following logic does not work with extensions. Until it's
+  // fixed let's rely on the renderer-side check. See https://crbug.com/895999.
+  if (!base::FeatureList::IsEnabled(network::features::kOutOfBlinkCors)) {
+    return false;
+  }
+
   const auto mode = request.fetch_request_mode;
   if (mode == network::mojom::FetchRequestMode::kNavigate ||
       mode == network::mojom::FetchRequestMode::kNoCors) {
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index 3605055b..d830713 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -2496,20 +2496,6 @@
   if (!node)
     node = delegate_->GetFrameTree()->root();
 
-  // Compute the url_to_load to check that it doesn't change through the
-  // function.
-  // TODO(clamy): Remove this once the root cause behind
-  // https://crbug.com/896028 has been found.
-  GURL url_to_load;
-  GURL virtual_url;
-  if (node->IsMainFrame()) {
-    bool reverse_on_redirect = false;
-    RewriteUrlForNavigation(params.url, browser_context_, &url_to_load,
-                            &virtual_url, &reverse_on_redirect);
-  } else {
-    url_to_load = params.url;
-  }
-
   // Compute overrides to the LoadURLParams for |override_user_agent|,
   // |should_replace_current_entry| and |has_user_gesture| that will be used
   // both in the creation of the NavigationEntry and the NavigationRequest.
@@ -2544,10 +2530,8 @@
     entry = CreateNavigationEntryFromLoadParams(
         node, params, override_user_agent, should_replace_current_entry,
         has_user_gesture);
-    CHECK_EQ(url_to_load, entry->GetFrameEntry(node)->url());
     DiscardPendingEntry(false);
     SetPendingEntry(std::move(entry));
-    CHECK_EQ(url_to_load, pending_entry_->GetFrameEntry(node)->url());
   }
 
   // Renderer-debug URLs are sent to the renderer process immediately for
@@ -2586,7 +2570,6 @@
   DCHECK(node->IsMainFrame() || !params.navigation_ui_data);
 
   DCHECK(pending_entry_);
-  CHECK_EQ(url_to_load, pending_entry_->GetFrameEntry(node)->url());
   std::unique_ptr<NavigationRequest> request =
       CreateNavigationRequestFromLoadParams(
           node, params, override_user_agent, should_replace_current_entry,
@@ -2734,9 +2717,7 @@
     const NavigationEntryImpl& entry,
     FrameNavigationEntry* frame_entry) {
   DCHECK_EQ(-1, GetIndexOfEntry(&entry));
-  // TODO(https://crbug.com/896028): Turn this CHECK into a DCHECK once the bug
-  // is fixed.
-  CHECK(frame_entry);
+  DCHECK(frame_entry);
 
   GURL url_to_load;
   GURL virtual_url;
@@ -2754,11 +2735,19 @@
     if (virtual_url.is_empty())
       virtual_url = url_to_load;
 
+    CHECK(virtual_url == entry.GetVirtualURL());
+
+    // This is a DCHECK and not a CHECK as URL rewrite has non-deterministic
+    // behavior in the field: it is possible for two calls to
+    // RewriteUrlForNavigation to return different results, leading to a
+    // different URL in the NavigationRequest and FrameEntry. This will be fixed
+    // once we remove the pending NavigationEntry, as we'll only make one call
+    // to RewriteUrlForNavigation.
+    DCHECK_EQ(url_to_load, frame_entry->url());
+
     // TODO(clamy): In order to remove the pending NavigationEntry,
     // |virtual_url| and |reverse_on_redirect| should be stored in the
     // NavigationRequest.
-    CHECK(virtual_url == entry.GetVirtualURL());
-    CHECK_EQ(url_to_load, frame_entry->url());
   } else {
     url_to_load = params.url;
     virtual_url = params.url;
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 4f2b00bb..be242dd 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -185,19 +185,29 @@
     const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context,
     const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
     const StoragePartition::OriginMatcherFunction& origin_matcher,
+    bool perform_cleanup,
     base::OnceClosure callback,
     const std::vector<SessionStorageUsageInfo>& infos) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
+  base::OnceClosure done_callback =
+      perform_cleanup
+          ? base::BindOnce(
+                &DOMStorageContextWrapper::PerformSessionStorageCleanup,
+                dom_storage_context, std::move(callback))
+          : std::move(callback);
+
+  base::RepeatingClosure barrier =
+      base::BarrierClosure(infos.size(), std::move(done_callback));
+
   for (size_t i = 0; i < infos.size(); ++i) {
     if (!origin_matcher.is_null() &&
         !origin_matcher.Run(infos[i].origin, special_storage_policy.get())) {
+      barrier.Run();
       continue;
     }
-    dom_storage_context->DeleteSessionStorage(infos[i]);
+    dom_storage_context->DeleteSessionStorage(infos[i], barrier);
   }
-
-  std::move(callback).Run();
 }
 
 void ClearLocalStorageOnUIThread(
@@ -233,12 +243,13 @@
     const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context,
     const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
     const StoragePartition::OriginMatcherFunction& origin_matcher,
+    bool perform_cleanup,
     base::OnceClosure callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   dom_storage_context->GetSessionStorageUsage(base::BindOnce(
       &OnSessionStorageUsageInfo, dom_storage_context, special_storage_policy,
-      origin_matcher, std::move(callback)));
+      origin_matcher, perform_cleanup, std::move(callback)));
 }
 
 }  // namespace
@@ -1171,7 +1182,7 @@
       ClearSessionStorageOnUIThread(
           base::WrapRefCounted(dom_storage_context),
           base::WrapRefCounted(special_storage_policy), origin_matcher,
-          decrement_callback);
+          perform_cleanup, decrement_callback);
     }
   }
 
diff --git a/content/public/browser/background_fetch_delegate.h b/content/public/browser/background_fetch_delegate.h
index 123d0db..5e6ed708 100644
--- a/content/public/browser/background_fetch_delegate.h
+++ b/content/public/browser/background_fetch_delegate.h
@@ -12,10 +12,12 @@
 #include "base/callback_forward.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/resource_request_info.h"
+#include "services/network/public/cpp/resource_request_body.h"
 #include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
@@ -23,7 +25,7 @@
 
 namespace gfx {
 class Size;
-}
+}  // namespace gfx
 
 namespace net {
 class HttpRequestHeaders;
@@ -60,6 +62,8 @@
   using GetIconDisplaySizeCallback = base::OnceCallback<void(const gfx::Size&)>;
   using GetPermissionForOriginCallback =
       base::OnceCallback<void(BackgroundFetchPermission)>;
+  using GetUploadDataCallback =
+      base::OnceCallback<void(scoped_refptr<network::ResourceRequestBody>)>;
 
   // Client interface that a BackgroundFetchDelegate would use to signal the
   // progress of a background fetch.
@@ -99,6 +103,12 @@
     // Called by the delegate when it's shutting down to signal that the
     // delegate is no longer valid.
     virtual void OnDelegateShutdown() = 0;
+
+    // Called by the Download Client when it needs the upload data for
+    // the given |download_guid|.
+    virtual void GetUploadData(const std::string& job_unique_id,
+                               const std::string& download_guid,
+                               GetUploadDataCallback callback) = 0;
   };
 
   BackgroundFetchDelegate();
@@ -132,7 +142,8 @@
       const std::string& method,
       const GURL& url,
       const net::NetworkTrafficAnnotationTag& traffic_annotation,
-      const net::HttpRequestHeaders& headers) = 0;
+      const net::HttpRequestHeaders& headers,
+      bool has_request_body) = 0;
 
   // Aborts any downloads associated with |job_unique_id|.
   virtual void Abort(const std::string& job_unique_id) = 0;
diff --git a/content/public/browser/dom_storage_context.h b/content/public/browser/dom_storage_context.h
index f909f54..5c1baa06 100644
--- a/content/public/browser/dom_storage_context.h
+++ b/content/public/browser/dom_storage_context.h
@@ -46,8 +46,10 @@
   virtual void PerformLocalStorageCleanup(base::OnceClosure callback) = 0;
 
   // Deletes the session storage data identified by |usage_info|.
-  virtual void DeleteSessionStorage(
-      const SessionStorageUsageInfo& usage_info) = 0;
+  virtual void DeleteSessionStorage(const SessionStorageUsageInfo& usage_info,
+                                    base::OnceClosure callback) = 0;
+
+  virtual void PerformSessionStorageCleanup(base::OnceClosure callback) = 0;
 
   // If this is called, sessionStorage data will be stored on disk, and can be
   // restored after a browser restart (with RecreateSessionStorage). This
diff --git a/content/public/test/android/BUILD.gn b/content/public/test/android/BUILD.gn
index 2bc36ac..5ba8e3b 100644
--- a/content/public/test/android/BUILD.gn
+++ b/content/public/test/android/BUILD.gn
@@ -45,6 +45,7 @@
     "javatests/src/org/chromium/content_public/browser/test/util/EqualityCriteria.java",
     "javatests/src/org/chromium/content_public/browser/test/util/HistoryUtils.java",
     "javatests/src/org/chromium/content_public/browser/test/util/JavaScriptUtils.java",
+    "javatests/src/org/chromium/content_public/browser/test/util/DomAutomationController.java",
     "javatests/src/org/chromium/content_public/browser/test/util/KeyUtils.java",
     "javatests/src/org/chromium/content_public/browser/test/util/RenderProcessLimit.java",
     "javatests/src/org/chromium/content_public/browser/test/util/TestCallbackHelperContainer.java",
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/DomAutomationController.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/DomAutomationController.java
new file mode 100644
index 0000000..7301e5a
--- /dev/null
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/DomAutomationController.java
@@ -0,0 +1,48 @@
+// 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.
+
+package org.chromium.content_public.browser.test.util;
+
+import org.chromium.content_public.browser.WebContents;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This class implements DomAutomationController.send by injecting Javascript into
+ * a page and polling for data.
+ */
+public class DomAutomationController {
+    private WebContents mWebContents;
+
+    /**
+     * Enables domAutomationController on the given webContents. Must be called after every
+     * page load.
+     */
+    public void inject(WebContents webContents) throws TimeoutException, InterruptedException {
+        mWebContents = webContents;
+        JavaScriptUtils.executeJavaScriptAndWaitForResult(mWebContents,
+                "window.domAutomationController = {"
+                        + "  data_: [],"
+                        + "  send: function(x) { this.data_.push(x) },"
+                        + "  hasData: function() { return this.data_.length > 0 },"
+                        + "  getData: function() { return this.data_.shift() }"
+                        + "}");
+    }
+
+    /**
+     * Waits until domAutomationController.send(value) has been called and returns value in JSON
+     * format.
+     */
+    public String waitForResult(String failureReason)
+            throws TimeoutException, InterruptedException {
+        assert mWebContents != null;
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            String result = JavaScriptUtils.executeJavaScriptAndWaitForResult(
+                    mWebContents, "domAutomationController.hasData()");
+            return result.equals("true");
+        }, failureReason);
+        return JavaScriptUtils.executeJavaScriptAndWaitForResult(
+                mWebContents, "domAutomationController.getData()");
+    }
+}
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/JavaScriptUtils.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/JavaScriptUtils.java
index ae8e6437..2850c44 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/JavaScriptUtils.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/JavaScriptUtils.java
@@ -57,6 +57,19 @@
     }
 
     /**
+     * Executes the given snippet of JavaScript code within the given WebContents and waits for a
+     * call to domAutomationController.send(). Returns the result from
+     * domAutomationController.send() in JSON format.
+     */
+    public static String runJavascriptWithAsyncResult(WebContents webContents, String code)
+            throws TimeoutException, InterruptedException {
+        DomAutomationController controller = new DomAutomationController();
+        controller.inject(webContents);
+        executeJavaScript(webContents, code);
+        return controller.waitForResult("No result for `" + code + "`");
+    }
+
+    /**
      * Executes the given snippet of JavaScript code but does not wait for the result.
      */
     public static void executeJavaScript(final WebContents webContents, final String code) {
diff --git a/content/shell/browser/layout_test/layout_test_background_fetch_delegate.cc b/content/shell/browser/layout_test/layout_test_background_fetch_delegate.cc
index 661b879d..8f8ff9789 100644
--- a/content/shell/browser/layout_test/layout_test_background_fetch_delegate.cc
+++ b/content/shell/browser/layout_test/layout_test_background_fetch_delegate.cc
@@ -199,7 +199,8 @@
     const std::string& method,
     const GURL& url,
     const net::NetworkTrafficAnnotationTag& traffic_annotation,
-    const net::HttpRequestHeaders& headers) {
+    const net::HttpRequestHeaders& headers,
+    bool has_request_body) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // Lazily create the |download_service_| because only very few layout tests
diff --git a/content/shell/browser/layout_test/layout_test_background_fetch_delegate.h b/content/shell/browser/layout_test/layout_test_background_fetch_delegate.h
index 26b5050..4e4bd72 100644
--- a/content/shell/browser/layout_test/layout_test_background_fetch_delegate.h
+++ b/content/shell/browser/layout_test/layout_test_background_fetch_delegate.h
@@ -38,7 +38,8 @@
                    const std::string& method,
                    const GURL& url,
                    const net::NetworkTrafficAnnotationTag& traffic_annotation,
-                   const net::HttpRequestHeaders& headers) override;
+                   const net::HttpRequestHeaders& headers,
+                   bool has_request_body) override;
   void Abort(const std::string& job_unique_id) override;
   void MarkJobComplete(const std::string& job_unique_id) override;
   void UpdateUI(const std::string& job_unique_id,
diff --git a/docs/windows_build_instructions.md b/docs/windows_build_instructions.md
index dbf874fb..b53b6b8 100644
--- a/docs/windows_build_instructions.md
+++ b/docs/windows_build_instructions.md
@@ -222,7 +222,7 @@
 (`gn args out/Default`) or on the gn gen command line
 (`gn gen out/Default --args="is_component_build = true is_debug = true"`).
 Some helpful settings to consider using include:
-* `use_jumbo_build = true` - *experimental* [Jumbo/unity](jumbo.md) builds.
+* `use_jumbo_build = true` - [Jumbo/unity](jumbo.md) builds.
 * `is_component_build = true` - this uses more, smaller DLLs, and incremental
 linking.
 * `enable_nacl = false` - this disables Native Client which is usually not
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index e5e3f05..e3950c5 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -891,6 +891,18 @@
       <message name="IDS_IOS_MANUAL_FALLBACK_MANAGE_ADDRESSES" desc="The title for the button in the manual fallback UI that takes the user to the addresses settings. In this screen they see all the addresses and can erase them. [30em]">
         Manage Addresses...
       </message>
+      <message name="IDS_IOS_MANUAL_FALLBACK_SHOW_ADDRESSES" desc="Label for the addresses icon in manual fallback. Read by Text To Speech" meaning="Voice Over will read this to the user followed by 'Button' when this button is focused.">
+        Addresses
+      </message>
+      <message name="IDS_IOS_MANUAL_FALLBACK_SHOW_CREDIT_CARDS" desc="Label for the credit cards icon in manual fallback. Read by Text To Speech" meaning="Voice Over will read this to the user followed by 'Button' when this button is focused.">
+        Credit Cards
+      </message>
+      <message name="IDS_IOS_MANUAL_FALLBACK_SHOW_KEYBOARD" desc="Label for the keyboard icon in manual fallback. Read by Text To Speech" meaning="Voice Over will read this to the user followed by 'Button' when this button is focused.">
+        Keyboard
+      </message>
+      <message name="IDS_IOS_MANUAL_FALLBACK_SHOW_PASSWORDS" desc="Label for the password icon in manual fallback. Read by Text To Speech" meaning="Voice Over will read this to the user followed by 'Button' when this button is focused.">
+        Passwords
+      </message>
       <message name="IDS_IOS_MICROPHONE_USAGE_DESCRIPTION" desc="Specifies the reason for accessing the user's microphone while the app is in use [Length: unlimited] [iOS only].">
         This lets you search faster using your voice.
       </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SHOW_ADDRESSES.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SHOW_ADDRESSES.png.sha1
new file mode 100644
index 0000000..72ad3af
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SHOW_ADDRESSES.png.sha1
@@ -0,0 +1 @@
+5297586726776d9e39145cccb665e2101d6f7fab
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SHOW_CREDIT_CARDS.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SHOW_CREDIT_CARDS.png.sha1
new file mode 100644
index 0000000..c35a01b
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SHOW_CREDIT_CARDS.png.sha1
@@ -0,0 +1 @@
+a535cc7ae4d44ff7243c5c868ce89d5a10a22613
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SHOW_KEYBOARD.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SHOW_KEYBOARD.png.sha1
new file mode 100644
index 0000000..eb89084
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SHOW_KEYBOARD.png.sha1
@@ -0,0 +1 @@
+35e0c0be1452b9f6a49c49f0fd5d8acde4383592
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SHOW_PASSWORDS.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SHOW_PASSWORDS.png.sha1
new file mode 100644
index 0000000..12694f54
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SHOW_PASSWORDS.png.sha1
@@ -0,0 +1 @@
+b3cc773022faae11faa1191f608ea8649fab54b5
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/OWNERS b/ios/chrome/app/strings/ios_strings_grd/OWNERS
new file mode 100644
index 0000000..f1a318c9
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/OWNERS
@@ -0,0 +1,4 @@
+per-file *.sha1=*
+
+# TEAM: ios-directory-owners@chromium.org
+# OS: iOS
diff --git a/ios/chrome/browser/find_in_page/find_in_page_js_unittest.mm b/ios/chrome/browser/find_in_page/find_in_page_js_unittest.mm
index 43f0314..bcd29d2 100644
--- a/ios/chrome/browser/find_in_page/find_in_page_js_unittest.mm
+++ b/ios/chrome/browser/find_in_page/find_in_page_js_unittest.mm
@@ -23,9 +23,10 @@
 
 namespace {
 
-// JavaScript invocation to search for 'foo' (for 1000 milliseconds).
-NSString* kJavaScriptToSearchForFoo =
-    @"__gCrWeb.findInPage.highlightWord('foo', false, 1000)";
+// JavaScript invocation format string, with one NSString placeholder for the
+// search target and timeout set to 1000ms.
+NSString* kJavaScriptSearchCallFormat =
+    @"__gCrWeb.findInPage.highlightWord('%@', 1000)";
 
 // Other JavaScript functions invoked by the tests.
 NSString* kJavaScriptIncrementIndex = @"__gCrWeb.findInPage.incrementIndex()";
@@ -97,7 +98,8 @@
 
     // Search for 'foo'. Performing the search sets the index to point to the
     // first visible occurrence of 'foo'.
-    ExecuteJavaScript(kJavaScriptToSearchForFoo);
+    ExecuteJavaScript(
+        [NSString stringWithFormat:kJavaScriptSearchCallFormat, @"foo"]);
     AssertJavaScriptValue(kJavaScriptIndex, 1);
     AssertJavaScriptValue(kJavaScriptSpansLength, kNumberOfFoosInHtml);
   }
@@ -194,7 +196,8 @@
 
   // Search for 'foo'. Performing the search sets the index to point to 0 since
   // there are no visible occurrences of 'foo'.
-  ExecuteJavaScript(kJavaScriptToSearchForFoo);
+  ExecuteJavaScript(
+      [NSString stringWithFormat:kJavaScriptSearchCallFormat, @"foo"]);
   AssertJavaScriptValue(kJavaScriptIndex, 0);
   AssertJavaScriptValue(kJavaScriptSpansLength, 6);
 
@@ -218,9 +221,8 @@
 
   // Search for the non-Ascii value. Performing the search sets the index to
   // point to the first visible occurrence of the non-Ascii.
-  NSString* result = ExecuteJavaScript([NSString
-      stringWithFormat:@"__gCrWeb.findInPage.highlightWord('%@', false, 1000)",
-                       kNonAscii]);
+  NSString* result = ExecuteJavaScript(
+      [NSString stringWithFormat:kJavaScriptSearchCallFormat, kNonAscii]);
   ASSERT_TRUE(result);
   AssertJavaScriptValue(kJavaScriptIndex, 0);
   AssertJavaScriptValue(kJavaScriptSpansLength, 1);
@@ -236,8 +238,8 @@
 
   // Search for space. Performing the search sets the index to
   // point to the first visible occurrence of the whitespace.
-  NSString* result =
-      ExecuteJavaScript(@"__gCrWeb.findInPage.highlightWord(' ', false, 1000)");
+  NSString* result = ExecuteJavaScript(
+      [NSString stringWithFormat:kJavaScriptSearchCallFormat, @" "]);
   ASSERT_TRUE(result);
   AssertJavaScriptValue(kJavaScriptIndex, 0);
   AssertJavaScriptValue(kJavaScriptSpansLength, 8);
diff --git a/ios/chrome/browser/find_in_page/js_findinpage_manager.mm b/ios/chrome/browser/find_in_page/js_findinpage_manager.mm
index 651eafb..9379221 100644
--- a/ios/chrome/browser/find_in_page/js_findinpage_manager.mm
+++ b/ios/chrome/browser/find_in_page/js_findinpage_manager.mm
@@ -30,7 +30,7 @@
 // to spend any time at runtime to format this constant into another constant.
 NSString* const kFindInPageVerbatim =
     @"window.__gCrWeb.findInPage && "
-     "window.__gCrWeb.findInPage.highlightWord(%@, false, 100.0);";
+     "window.__gCrWeb.findInPage.highlightWord(%@, 100.0);";
 
 // The timeout of 100ms is hardcoded into this string so we don't have
 // to spend any time at runtime to format this constant into another constant.
diff --git a/ios/chrome/browser/find_in_page/resources/find_in_page.js b/ios/chrome/browser/find_in_page/resources/find_in_page.js
index 2cd1c79c..1b1d60f9 100644
--- a/ios/chrome/browser/find_in_page/resources/find_in_page.js
+++ b/ios/chrome/browser/find_in_page/resources/find_in_page.js
@@ -107,27 +107,10 @@
 /**
  * Creates the regex needed to find the text.
  * @param {string} findText Phrase to look for.
- * @param {boolean} opt_split True to split up the phrase.
  * @return {RegExp} regex needed to find the text.
  */
-function getRegex_(findText, opt_split) {
-  let regexString = '';
-  if (opt_split) {
-    let words = [];
-    let split = findText.split(' ');
-    for (let i = 0; i < split.length; i++) {
-      words.push(escapeRegex_(split[i]));
-    }
-    let joinedWords = words.join('|');
-    regexString = '(' +
-        // Match at least one word.
-        '\\b(?:' + joinedWords + ')' +
-        // Include zero or more additional words separated by whitespace.
-        '(?:\\s*\\b(?:' + joinedWords + '))*' +
-        ')';
-  } else {
-    regexString = '(' + escapeRegex_(findText) + ')';
-  }
+function getRegex_(findText) {
+  let regexString = '(' + escapeRegex_(findText) + ')';
   return new RegExp(regexString, 'ig');
 };
 
@@ -153,14 +136,11 @@
 /**
  * Looks for a phrase in the DOM.
  * @param {string} findText Phrase to look for like "ben franklin".
- * @param {boolean} opt_split True to split up the words and look for any
- *     of them.  False to require the full phrase to be there.
- *     Undefined will try the full phrase, and if nothing is found do the split.
  * @param {number} timeout Maximum time to run.
  * @return {string} How many results there are in the page in the form of
        [highlightedWordsCount, [index, pageLocationX, pageLocationY]].
  */
-__gCrWeb.findInPage.highlightWord = function(findText, opt_split, timeout) {
+__gCrWeb.findInPage.highlightWord = function(findText, timeout) {
   if (__gCrWeb.findInPage.spans && __gCrWeb.findInPage.spans.length) {
     // Clean up a previous run.
     clearHighlight_();
@@ -193,7 +173,7 @@
   __gCrWeb.findInPage.replacementsIndex = 0;
   __gCrWeb.findInPage.replacementNewNodesIndex = 0;
 
-  __gCrWeb.findInPage.regex = getRegex_(findText, opt_split);
+  __gCrWeb.findInPage.regex = getRegex_(findText);
 
   searchInProgress_ = true;
 
@@ -209,7 +189,6 @@
                     whether the text was found and int idicates text position.
  */
 __gCrWeb.findInPage.pumpSearch = function(timeout) {
-  let opt_split = false;
   // TODO(justincohen): It would be better if this DCHECKed.
   if (searchInProgress_ == false)
     return NO_RESULTS;
@@ -335,25 +314,11 @@
 
   searchInProgress_ = false;
 
-  // Try again flow.
-  // If opt_split is true, we are done since we won't do any better.
-  // If opt_split is false, they were explicit about wanting the full thing
-  // so do not try with a split.
-  // If opt_split is undefined and we did not find an answer, go ahead and try
-  // splitting the terms.
-  if (__gCrWeb.findInPage.spans.length == 0 && opt_split === undefined) {
-    // Try to be more aggressive:
-    return __gCrWeb.findInPage.highlightWord(findText, true);
+  let pos = __gCrWeb.findInPage.goNext();
+  if (pos) {
+    return '[' + __gCrWeb.findInPage.visibleFound + ',' + pos + ']';
   } else {
-    let pos = __gCrWeb.findInPage.goNext();
-    if (pos) {
-      return '[' + __gCrWeb.findInPage.visibleFound + ',' + pos + ']';
-    } else if (opt_split === undefined) {
-      // Nothing visible, go ahead and be more aggressive.
-      return __gCrWeb.findInPage.highlightWord(findText, true);
-    } else {
-      return NO_RESULTS;
-    }
+    return NO_RESULTS;
   }
 };
 
@@ -652,20 +617,6 @@
 };
 
 /**
- * When the GSA app detects a zoom change, we need to update our css.
- * @param {number} width Width of page.
- * @param {number} height Height of page.
- */
-function fixZoom_(width, height) {
-  pageWidth_ = width;
-  pageHeight_ = height;
-  if (styleElement_) {
-    removeStyle_();
-    addStyle_();
-  }
-};
-
-/**
  * Enable the __gCrWeb.findInPage module.
  * Mainly just adds the style for the classes.
  */
diff --git a/ios/chrome/browser/prefs/BUILD.gn b/ios/chrome/browser/prefs/BUILD.gn
index fffd7eb61..89dc301d 100644
--- a/ios/chrome/browser/prefs/BUILD.gn
+++ b/ios/chrome/browser/prefs/BUILD.gn
@@ -36,6 +36,7 @@
     "//components/flags_ui",
     "//components/gcm_driver",
     "//components/handoff",
+    "//components/invalidation/impl:impl",
     "//components/language/core/browser",
     "//components/metrics",
     "//components/network_time",
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm
index 49f7874..8901464 100644
--- a/ios/chrome/browser/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -11,6 +11,8 @@
 #include "components/flags_ui/pref_service_flags_storage.h"
 #include "components/gcm_driver/gcm_channel_status_syncer.h"
 #import "components/handoff/handoff_manager.h"
+#include "components/invalidation/impl/invalidator_registrar_with_memory.h"
+#include "components/invalidation/impl/per_user_topic_registration_manager.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/network_time/network_time_tracker.h"
@@ -121,6 +123,8 @@
   RegisterVoiceSearchBrowserStatePrefs(registry);
   sync_sessions::SessionSyncPrefs::RegisterProfilePrefs(registry);
   syncer::SyncPrefs::RegisterProfilePrefs(registry);
+  syncer::PerUserTopicRegistrationManager::RegisterProfilePrefs(registry);
+  syncer::InvalidatorRegistrarWithMemory::RegisterProfilePrefs(registry);
   TemplateURLPrepopulateData::RegisterProfilePrefs(registry);
   translate::TranslatePrefs::RegisterProfilePrefs(registry);
   unified_consent::UnifiedConsentService::RegisterPrefs(registry);
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.h b/ios/chrome/browser/sync/ios_chrome_sync_client.h
index 803901d..f68d5a4 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.h
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.h
@@ -48,8 +48,7 @@
   sync_sessions::SessionSyncService* GetSessionSyncService() override;
   bool HasPasswordStore() override;
   base::Closure GetPasswordStateChangedCallback() override;
-  syncer::DataTypeController::TypeVector CreateDataTypeControllers(
-      syncer::LocalDeviceInfoProvider* local_device_info_provider) override;
+  syncer::DataTypeController::TypeVector CreateDataTypeControllers() override;
   autofill::PersonalDataManager* GetPersonalDataManager() override;
   invalidation::InvalidationService* GetInvalidationService() override;
   BookmarkUndoService* GetBookmarkUndoServiceIfExists() override;
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index d184fa5b..1be3bdb0 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -180,11 +180,10 @@
 }
 
 syncer::DataTypeController::TypeVector
-IOSChromeSyncClient::CreateDataTypeControllers(
-    syncer::LocalDeviceInfoProvider* local_device_info_provider) {
+IOSChromeSyncClient::CreateDataTypeControllers() {
   // The iOS port does not have any platform-specific datatypes.
   return component_factory_->CreateCommonDataTypeControllers(
-      GetDisabledTypesFromCommandLine(), local_device_info_provider);
+      GetDisabledTypesFromCommandLine());
 }
 
 BookmarkUndoService* IOSChromeSyncClient::GetBookmarkUndoServiceIfExists() {
@@ -264,11 +263,6 @@
       NOTREACHED();
       return base::WeakPtr<syncer::SyncableService>();
     }
-    case syncer::SESSIONS: {
-      return SessionSyncServiceFactory::GetForBrowserState(browser_state_)
-          ->GetSyncableService()
-          ->AsWeakPtr();
-    }
     case syncer::PASSWORDS: {
       return password_store_ ? password_store_->GetPasswordSyncableService()
                              : base::WeakPtr<syncer::SyncableService>();
diff --git a/ios/chrome/browser/sync/profile_sync_service_factory.cc b/ios/chrome/browser/sync/profile_sync_service_factory.cc
index d82beec2..491708f 100644
--- a/ios/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/ios/chrome/browser/sync/profile_sync_service_factory.cc
@@ -153,8 +153,6 @@
       GetApplicationContext()->GetNetworkConnectionTracker();
   init_params.debug_identifier = browser_state->GetDebugName();
   init_params.channel = ::GetChannel();
-  init_params.user_events_separate_pref_group =
-      unified_consent::IsUnifiedConsentFeatureEnabled();
 
   bool use_fcm_invalidations =
       base::FeatureList::IsEnabled(invalidation::switches::kFCMInvalidations);
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator.mm b/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator.mm
index fa6f48f..d00ea0e 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator.mm
@@ -5,8 +5,8 @@
 #import "ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator.h"
 
 #include "base/memory/ref_counted.h"
+#include "base/metrics/user_metrics.h"
 #include "base/strings/sys_string_conversions.h"
-
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/ios/browser/autofill_driver_ios.h"
 #include "components/keyed_service/core/service_access_type.h"
@@ -77,8 +77,8 @@
 - (void)stop {
   [super stop];
   if (![self dismissIfNecessaryThenDoCompletion:nil]) {
-    // TODO(crbug.com/845472): merge with password coordinator and explain why
-    // we remove from super view when we can't dismiss.
+    // dismissIfNecessaryThenDoCompletion dismisses, via the UIKit API, only
+    // for popovers (iPads). For iPhones we need to remove the view.
     [self.viewController.view removeFromSuperview];
   }
 }
@@ -87,6 +87,7 @@
 
 - (void)popoverPresentationControllerDidDismissPopover:
     (UIPopoverPresentationController*)popoverPresentationController {
+  base::RecordAction(base::UserMetricsAction("ManualFallback_ClosePopover"));
   [self.delegate resetAccessoryView];
 }
 
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.mm
index 42f58c8..c84d0c8 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.mm
@@ -9,6 +9,8 @@
 #import "ios/chrome/browser/ui/autofill/manual_fill/uicolor_manualfill.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -109,6 +111,7 @@
 
 - (void)loadView {
   self.view = [[UIView alloc] init];
+  self.view.accessibilityViewIsModal = YES;
   self.view.translatesAutoresizingMaskIntoConstraints = NO;
 
   UIColor* tintColor = [self activeTintColor];
@@ -125,6 +128,8 @@
                   forControlEvents:UIControlEventTouchUpInside];
     self.keyboardButton.accessibilityIdentifier =
         manual_fill::AccessoryKeyboardAccessibilityIdentifier;
+    self.keyboardButton.accessibilityLabel =
+        l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_SHOW_KEYBOARD);
     [icons addObject:self.keyboardButton];
   }
 
@@ -139,6 +144,8 @@
   self.passwordButton.accessibilityIdentifier =
       manual_fill::AccessoryPasswordAccessibilityIdentifier;
   self.passwordButton.hidden = self.isPasswordButtonHidden;
+  self.passwordButton.accessibilityLabel =
+      l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_SHOW_PASSWORDS);
   [icons addObject:self.passwordButton];
 
   if (autofill::features::IsAutofillManualFallbackEnabled()) {
@@ -153,6 +160,8 @@
     self.cardsButton.accessibilityIdentifier =
         manual_fill::AccessoryCreditCardAccessibilityIdentifier;
     self.cardsButton.hidden = self.isCreditCardButtonHidden;
+    self.cardsButton.accessibilityLabel =
+        l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_SHOW_CREDIT_CARDS);
     [icons addObject:self.cardsButton];
 
     self.accountButton = [UIButton buttonWithType:UIButtonTypeSystem];
@@ -166,6 +175,8 @@
     self.accountButton.accessibilityIdentifier =
         manual_fill::AccessoryAddressAccessibilityIdentifier;
     self.accountButton.hidden = self.isAddressButtonHidden;
+    self.accountButton.accessibilityLabel =
+        l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_SHOW_ADDRESSES);
     [icons addObject:self.accountButton];
   }
   UIStackView* stackView = [[UIStackView alloc] initWithArrangedSubviews:icons];
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h
index ac218d5..8fe3d24 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h
+++ b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h
@@ -5,9 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_UI_AUTOFILL_MANUAL_FILL_PASSWORD_COORDINATOR_H_
 #define IOS_CHROME_BROWSER_UI_AUTOFILL_MANUAL_FILL_PASSWORD_COORDINATOR_H_
 
-#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
+#import "ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator.h"
 
-@class ManualFillInjectionHandler;
 class WebStateList;
 
 namespace manual_fill {
@@ -17,10 +16,7 @@
 }  // namespace manual_fill
 
 // Delegate for the coordinator actions.
-@protocol PasswordCoordinatorDelegate<NSObject>
-
-// Resets the accessory view.
-- (void)resetAccessoryView;
+@protocol PasswordCoordinatorDelegate<FallbackCoordinatorDelegate>
 
 // Opens the passwords settings.
 - (void)openPasswordSettings;
@@ -30,12 +26,10 @@
 // Creates and manages a view controller to present passwords to the user.
 // Any selected password will be sent to the current field in the active web
 // state.
-@interface ManualFillPasswordCoordinator : ChromeCoordinator
+@interface ManualFillPasswordCoordinator : FallbackCoordinator
 
-// The view controller of this coordinator.
-@property(nonatomic, readonly) UIViewController* viewController;
-
-// The delegate for this coordinator.
+// The delegate for this coordinator. Delegate class extends
+// FallbackCoordinatorDelegate, and replaces super class delegate.
 @property(nonatomic, weak) id<PasswordCoordinatorDelegate> delegate;
 
 // Creates a coordinator that uses a |viewController|, |browserState|,
@@ -44,12 +38,15 @@
 initWithBaseViewController:(UIViewController*)viewController
               browserState:(ios::ChromeBrowserState*)browserState
               webStateList:(WebStateList*)webStateList
-          injectionHandler:(ManualFillInjectionHandler*)injectionHandler;
+          injectionHandler:(ManualFillInjectionHandler*)injectionHandler
+    NS_DESIGNATED_INITIALIZER;
 
-// Unavailable, use -initWithBaseViewController:browserState:webStateList:.
-- (instancetype)initWithBaseViewController:(UIViewController*)viewController
-                              browserState:
-                                  (ios::ChromeBrowserState*)browserState
+// Unavailable, use
+// -initWithBaseViewController:browserState:webStateList:injectionHandler:.
+- (instancetype)
+initWithBaseViewController:(UIViewController*)viewController
+              browserState:(ios::ChromeBrowserState*)browserState
+          injectionHandler:(ManualFillInjectionHandler*)injectionHandler
     NS_UNAVAILABLE;
 
 // Presents the password view controller as a popover from the passed button.
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm
index 51f9aee..8c8edf3 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm
@@ -4,7 +4,6 @@
 
 #import "ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h"
 
-#include "base/metrics/user_metrics.h"
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
@@ -30,8 +29,7 @@
 
 @interface ManualFillPasswordCoordinator ()<
     PasswordListDelegate,
-    UIViewControllerTransitioningDelegate,
-    UIPopoverPresentationControllerDelegate>
+    UIViewControllerTransitioningDelegate>
 
 // Fetches and filters the passwords for the view controller.
 @property(nonatomic, strong) ManualFillPasswordMediator* passwordMediator;
@@ -44,11 +42,6 @@
 // passwords. Owned by the view controllers hierarchy.
 @property(nonatomic, weak) PasswordViewController* allPasswordsViewController;
 
-// The object in charge of interacting with the web view. Used to fill the data
-// in the forms.
-@property(nonatomic, strong)
-    ManualFillInjectionHandler* manualFillInjectionHandler;
-
 // Button presenting this coordinator in a popover. Used for continuation after
 // dismissing any presented view controller. iPad only.
 @property(nonatomic, weak) UIButton* presentingButton;
@@ -57,10 +50,10 @@
 
 @implementation ManualFillPasswordCoordinator
 
-@synthesize allPasswordsViewController = _allPasswordsViewController;
-@synthesize manualFillInjectionHandler = _manualFillInjectionHandler;
-@synthesize passwordMediator = _passwordMediator;
-@synthesize passwordViewController = _passwordViewController;
+// Property tagged dynamic because it overrides super class delegate with and
+// extension of the super delegate type (i.e. PasswordCoordinatorDelegate
+// extends FallbackCoordinatorDelegate)
+@dynamic delegate;
 
 - (instancetype)
 initWithBaseViewController:(UIViewController*)viewController
@@ -68,12 +61,12 @@
               webStateList:(WebStateList*)webStateList
           injectionHandler:(ManualFillInjectionHandler*)injectionHandler {
   self = [super initWithBaseViewController:viewController
-                              browserState:browserState];
+                              browserState:browserState
+                          injectionHandler:injectionHandler];
   if (self) {
     _passwordViewController =
         [[PasswordViewController alloc] initWithSearchController:nil];
     _passwordViewController.contentInsetsAlwaysEqualToSafeArea = YES;
-    _manualFillInjectionHandler = injectionHandler;
 
     auto passwordStore = IOSChromePasswordStoreFactory::GetForBrowserState(
         browserState, ServiceAccessType::EXPLICIT_ACCESS);
@@ -82,47 +75,20 @@
                                                    passwordStore:passwordStore];
     _passwordMediator.consumer = _passwordViewController;
     _passwordMediator.navigationDelegate = self;
-    _passwordMediator.contentDelegate = _manualFillInjectionHandler;
+    _passwordMediator.contentDelegate = injectionHandler;
   }
   return self;
 }
 
 - (void)stop {
-  if (IsIPadIdiom() && self.passwordViewController.presentingViewController) {
-    [self.passwordViewController dismissViewControllerAnimated:true
-                                                    completion:nil];
-  } else {
-    [self.passwordViewController.view removeFromSuperview];
-  }
+  [super stop];
   [self.allPasswordsViewController dismissViewControllerAnimated:YES
                                                       completion:nil];
 }
 
-- (UIViewController*)viewController {
-  return self.passwordViewController;
-}
-
 - (void)presentFromButton:(UIButton*)button {
+  [super presentFromButton:button];
   self.presentingButton = button;
-  self.passwordViewController.modalPresentationStyle =
-      UIModalPresentationPopover;
-
-  // The |button.window.rootViewController| is used in order to present above
-  // the keyboard. This way the popover will be dismissed on keyboard
-  // interaction and it won't be covered when the keyboard is near the top of
-  // the screen.
-  [button.window.rootViewController
-      presentViewController:self.passwordViewController
-                   animated:YES
-                 completion:nil];
-
-  UIPopoverPresentationController* popoverPresentationController =
-      self.passwordViewController.popoverPresentationController;
-  popoverPresentationController.sourceView = button;
-  popoverPresentationController.sourceRect = button.bounds;
-  popoverPresentationController.permittedArrowDirections =
-      UIPopoverArrowDirectionUp | UIMenuControllerArrowDown;
-  popoverPresentationController.delegate = self;
 }
 
 #pragma mark - UIViewControllerTransitioningDelegate
@@ -171,6 +137,12 @@
   return animator;
 }
 
+#pragma mark - FallbackCoordinator
+
+- (UIViewController*)viewController {
+  return self.passwordViewController;
+}
+
 #pragma mark - PasswordListDelegate
 
 - (void)openAllPasswordsList {
@@ -226,24 +198,10 @@
 }
 
 - (void)openPasswordSettings {
-  // On iPad, dismiss the popover before the settings are presented.
-  if (IsIPadIdiom() && self.passwordViewController.presentingViewController) {
-    [self.passwordViewController
-        dismissViewControllerAnimated:true
-                           completion:^{
-                             [self openPasswordSettings];
-                           }];
-    return;
-  }
-  [self.delegate openPasswordSettings];
-}
-
-#pragma mark - UIPopoverPresentationControllerDelegate
-
-- (void)popoverPresentationControllerDidDismissPopover:
-    (UIPopoverPresentationController*)popoverPresentationController {
-  base::RecordAction(base::UserMetricsAction("ManualFallback_ClosePopover"));
-  [self.delegate resetAccessoryView];
+  __weak id<PasswordCoordinatorDelegate> delegate = self.delegate;
+  [self dismissIfNecessaryThenDoCompletion:^{
+    [delegate openPasswordSettings];
+  }];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_egtest.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_egtest.mm
index 0c257e5..9e7dda4 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_egtest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_egtest.mm
@@ -156,11 +156,11 @@
   ios::ChromeBrowserState* browserState =
       chrome_test_util::GetOriginalBrowserState();
 
-  // Resets the Service associated with this browserState to a service with
-  // default providers. The previous service is deleted.
+  // Resets the Service associated with this browserState to a new service with
+  // no providers. The previous service is deleted.
   IOSChromeContentSuggestionsServiceFactory::GetInstance()->SetTestingFactory(
       browserState,
-      base::BindRepeating(&CreateChromeContentSuggestionsServiceWithProviders));
+      base::BindRepeating(&CreateChromeContentSuggestionsService));
   [super tearDown];
 }
 
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
index e3d9ffaf..e29df69 100644
--- a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
@@ -118,11 +118,11 @@
       chrome_test_util::GetOriginalBrowserState();
   ReadingListModelFactory::GetForBrowserState(browserState)->DeleteAllEntries();
 
-  // Resets the Service associated with this browserState to a service with
-  // default providers. The previous service is deleted.
+  // Resets the Service associated with this browserState to a new service with
+  // no providers. The previous service is deleted.
   IOSChromeContentSuggestionsServiceFactory::GetInstance()->SetTestingFactory(
       browserState,
-      base::BindRepeating(&CreateChromeContentSuggestionsServiceWithProviders));
+      base::BindRepeating(&CreateChromeContentSuggestionsService));
   [super tearDown];
 }
 
diff --git a/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.mm b/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.mm
index 09659bb..4dc366b 100644
--- a/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.mm
+++ b/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.mm
@@ -374,12 +374,22 @@
   [parentView addSubview:self.view];
   self.view.accessibilityIdentifier = kFindInPageContainerViewId;
 
+  // Make sure that the Find in Page view bottom constraint has a lower priority
+  // than the constraint making sure that it doesn't overlap with the status
+  // bar.
+  NSLayoutConstraint* bottomConstraint =
+      [self.view.bottomAnchor constraintEqualToAnchor:toolbarView.bottomAnchor];
+  bottomConstraint.priority = UILayoutPriorityRequired - 1;
+
   [NSLayoutConstraint activateConstraints:@[
     [self.view.leadingAnchor constraintEqualToAnchor:parentView.leadingAnchor],
     [self.view.trailingAnchor
         constraintEqualToAnchor:parentView.trailingAnchor],
+    bottomConstraint,
+    [self.findBarView.topAnchor
+        constraintGreaterThanOrEqualToAnchor:self.view.safeAreaLayoutGuide
+                                                 .topAnchor],
     [self.view.topAnchor constraintEqualToAnchor:parentView.topAnchor],
-    [self.view.bottomAnchor constraintEqualToAnchor:toolbarView.bottomAnchor],
   ]];
 
   CGFloat duration = animated ? kAnimationDuration : 0;
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
index e84c028..a8cae9b1 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
@@ -27,7 +27,7 @@
 namespace {
 const int kRowCount = 6;
 const CGFloat kRowHeight = 48.0;
-const CGFloat kShortcutsRowHeight = 320;
+const CGFloat kShortcutsRowHeight = 220;
 const CGFloat kAnswerRowHeight = 64.0;
 const CGFloat kTopAndBottomPadding = 8.0;
 UIColor* BackgroundColorTablet() {
diff --git a/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm b/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
index 29e051d..a8ebafa 100644
--- a/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
@@ -1431,6 +1431,11 @@
 // any device. To limit the effect of (2), custom large scrolling steps are
 // added to the usual scrolling actions.
 - (void)testManyPasswords {
+  if (IsIPadIdiom()) {
+    // TODO(crbug.com/906551): Enable the test on iPad once the bug is fixed.
+    EARL_GREY_TEST_DISABLED(@"Disabled for iPad.");
+  }
+
   // Enough just to ensure filling more than one page on all devices.
   constexpr int kPasswordsCount = 15;
 
diff --git a/ios/web_view/internal/sync/web_view_sync_client.h b/ios/web_view/internal/sync/web_view_sync_client.h
index 952f02167..2170087 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.h
+++ b/ios/web_view/internal/sync/web_view_sync_client.h
@@ -43,8 +43,7 @@
   sync_sessions::SessionSyncService* GetSessionSyncService() override;
   bool HasPasswordStore() override;
   base::RepeatingClosure GetPasswordStateChangedCallback() override;
-  syncer::DataTypeController::TypeVector CreateDataTypeControllers(
-      syncer::LocalDeviceInfoProvider* local_device_info_provider) override;
+  syncer::DataTypeController::TypeVector CreateDataTypeControllers() override;
   autofill::PersonalDataManager* GetPersonalDataManager() override;
   invalidation::InvalidationService* GetInvalidationService() override;
   BookmarkUndoService* GetBookmarkUndoServiceIfExists() override;
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm
index 5792531a..64979b3 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.mm
+++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -140,11 +140,10 @@
 }
 
 syncer::DataTypeController::TypeVector
-WebViewSyncClient::CreateDataTypeControllers(
-    syncer::LocalDeviceInfoProvider* local_device_info_provider) {
+WebViewSyncClient::CreateDataTypeControllers() {
   // The iOS port does not have any platform-specific datatypes.
   return component_factory_->CreateCommonDataTypeControllers(
-      GetDisabledTypes(), local_device_info_provider);
+      GetDisabledTypes());
 }
 
 BookmarkUndoService* WebViewSyncClient::GetBookmarkUndoServiceIfExists() {
diff --git a/media/gpu/v4l2/v4l2_image_processor.cc b/media/gpu/v4l2/v4l2_image_processor.cc
index 9850b93..9ad15287 100644
--- a/media/gpu/v4l2/v4l2_image_processor.cc
+++ b/media/gpu/v4l2/v4l2_image_processor.cc
@@ -68,26 +68,18 @@
 V4L2ImageProcessor::V4L2ImageProcessor(scoped_refptr<V4L2Device> device,
                                        v4l2_memory input_memory_type,
                                        v4l2_memory output_memory_type,
-                                       VideoPixelFormat input_format,
-                                       VideoPixelFormat output_format,
+                                       const VideoFrameLayout& input_layout,
+                                       const VideoFrameLayout& output_layout,
                                        gfx::Size input_visible_size,
-                                       gfx::Size input_allocated_size,
                                        gfx::Size output_visible_size,
-                                       gfx::Size output_allocated_size,
-                                       size_t input_planes_count,
-                                       size_t output_planes_count,
                                        size_t num_buffers,
                                        const base::Closure& error_cb)
-    : input_visible_size_(input_visible_size),
-      input_allocated_size_(input_allocated_size),
-      output_visible_size_(output_visible_size),
-      output_allocated_size_(output_allocated_size),
-      input_format_(input_format),
-      output_format_(output_format),
+    : input_layout_(input_layout),
+      input_visible_size_(input_visible_size),
       input_memory_type_(input_memory_type),
+      output_layout_(output_layout),
+      output_visible_size_(output_visible_size),
       output_memory_type_(output_memory_type),
-      input_planes_count_(input_planes_count),
-      output_planes_count_(output_planes_count),
       child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       device_(device),
       device_thread_("V4L2ImageProcessorThread"),
@@ -133,12 +125,10 @@
       scoped_refptr<V4L2Device> device,
       v4l2_memory input_memory_type,
       v4l2_memory output_memory_type,
-      VideoPixelFormat input_format,
-      VideoPixelFormat output_format,
+      const VideoFrameLayout& input_layout,
+      const VideoFrameLayout& output_layout,
       gfx::Size input_visible_size,
-      gfx::Size input_allocated_size,
       gfx::Size output_visible_size,
-      gfx::Size output_allocated_size,
       size_t num_buffers,
       const base::Closure& error_cb) {
   VLOGF(2);
@@ -157,10 +147,10 @@
     return nullptr;
   }
   const uint32_t input_format_fourcc =
-      V4L2Device::VideoPixelFormatToV4L2PixFmt(input_format);
+      V4L2Device::VideoPixelFormatToV4L2PixFmt(input_layout.format());
   if (!device->Open(V4L2Device::Type::kImageProcessor, input_format_fourcc)) {
     VLOGF(1) << "Failed to open device for input format: "
-             << VideoPixelFormatToString(input_format)
+             << VideoPixelFormatToString(input_layout.format())
              << " fourcc: " << FourccToString(input_format_fourcc);
     return nullptr;
   }
@@ -169,21 +159,26 @@
   struct v4l2_format format;
   memset(&format, 0, sizeof(format));
   format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-  format.fmt.pix_mp.width = input_allocated_size.width();
-  format.fmt.pix_mp.height = input_allocated_size.height();
+  format.fmt.pix_mp.width = input_layout.coded_size().width();
+  format.fmt.pix_mp.height = input_layout.coded_size().height();
   format.fmt.pix_mp.pixelformat = input_format_fourcc;
   if (device->Ioctl(VIDIOC_S_FMT, &format) != 0) {
     VLOGF(1) << "Failed to negotiate input format";
     return nullptr;
   }
-  const size_t input_planes_count = format.fmt.pix_mp.num_planes;
-  DCHECK_LE(input_planes_count, static_cast<size_t>(VIDEO_MAX_PLANES));
-  const gfx::Size negotiated_input_allocated_size =
-      V4L2Device::CodedSizeFromV4L2Format(format);
-  if (!gfx::Rect(negotiated_input_allocated_size)
+
+  base::Optional<VideoFrameLayout> negotiated_input_layout =
+      V4L2Device::V4L2FormatToVideoFrameLayout(format);
+  if (!negotiated_input_layout) {
+    VLOGF(1) << "Failed to negotiate input VideoFrameLayout";
+    return nullptr;
+  }
+  DCHECK_LE(negotiated_input_layout->num_buffers(),
+            static_cast<size_t>(VIDEO_MAX_PLANES));
+  if (!gfx::Rect(negotiated_input_layout->coded_size())
       .Contains(gfx::Rect(input_visible_size))) {
     VLOGF(1) << "Negotiated input allocated size: "
-             << negotiated_input_allocated_size.ToString()
+             << negotiated_input_layout->coded_size().ToString()
              << " should contain visible size: "
              << input_visible_size.ToString();
     return nullptr;
@@ -192,32 +187,36 @@
   // Try to set output format.
   memset(&format, 0, sizeof(format));
   format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-  format.fmt.pix_mp.width = output_allocated_size.width();
-  format.fmt.pix_mp.height = output_allocated_size.height();
+  format.fmt.pix_mp.width = output_layout.coded_size().width();
+  format.fmt.pix_mp.height = output_layout.coded_size().height();
   format.fmt.pix_mp.pixelformat =
-      V4L2Device::VideoPixelFormatToV4L2PixFmt(output_format);
+      V4L2Device::VideoPixelFormatToV4L2PixFmt(output_layout.format());
   if (device->Ioctl(VIDIOC_S_FMT, &format) != 0) {
     VLOGF(1) << "Failed to negotiate output format";
     return nullptr;
   }
-  const size_t output_planes_count = format.fmt.pix_mp.num_planes;
-  DCHECK_LE(output_planes_count, static_cast<size_t>(VIDEO_MAX_PLANES));
-  const gfx::Size negotiated_output_allocated_size =
-      V4L2Device::CodedSizeFromV4L2Format(format);
-  if (!gfx::Rect(negotiated_output_allocated_size)
-      .Contains(gfx::Rect(output_allocated_size))) {
-    VLOGF(1) << "Negotiated output allocated size: "
-             << negotiated_output_allocated_size.ToString()
-             << " should contain original output allocated size: "
-             << output_allocated_size.ToString();
+  base::Optional<VideoFrameLayout> negotiated_output_layout =
+      V4L2Device::V4L2FormatToVideoFrameLayout(format);
+  if (!negotiated_output_layout) {
+    VLOGF(1) << "Failed to negotiate output VideoFrameLayout";
     return nullptr;
   }
+  DCHECK_LE(negotiated_output_layout->num_buffers(),
+            static_cast<size_t>(VIDEO_MAX_PLANES));
+  if (!gfx::Rect(negotiated_output_layout->coded_size())
+      .Contains(gfx::Rect(output_layout.coded_size()))) {
+    VLOGF(1) << "Negotiated output allocated size: "
+             << negotiated_output_layout->coded_size().ToString()
+             << " should contain original output allocated size: "
+             << output_layout.coded_size().ToString();
+    return nullptr;
+
+  }
 
   auto processor = base::WrapUnique(new V4L2ImageProcessor(
-      std::move(device), input_memory_type, output_memory_type, input_format,
-      output_format, input_visible_size, negotiated_input_allocated_size,
-      output_visible_size, negotiated_output_allocated_size, input_planes_count,
-      output_planes_count, num_buffers, std::move(error_cb)));
+      std::move(device), input_memory_type, output_memory_type,
+      *negotiated_input_layout, *negotiated_output_layout, input_visible_size,
+      output_visible_size, num_buffers, std::move(error_cb)));
   if (!processor->Initialize()) {
     VLOGF(1) << "Failed to initialize V4L2ImageProcessor";
     return nullptr;
@@ -251,14 +250,10 @@
       base::Bind(&V4L2ImageProcessor::StartDevicePoll, base::Unretained(this)));
 
   VLOGF(2) << "V4L2ImageProcessor initialized for "
-           << " input_format:" << VideoPixelFormatToString(input_format_)
-           << ", output_format:" << VideoPixelFormatToString(output_format_)
+           << "input_layout: " << input_layout_
+           << ", output_layout: " << output_layout_
            << ", input_visible_size: " << input_visible_size_.ToString()
-           << ", input_allocated_size: " << input_allocated_size_.ToString()
-           << ", input_planes_count: " << input_planes_count_
-           << ", output_visible_size: " << output_visible_size_.ToString()
-           << ", output_allocated_size: " << output_allocated_size_.ToString()
-           << ", output_planes_count: " << output_planes_count_;
+           << ", output_visible_size: " << output_visible_size_.ToString();
 
   return true;
 }
@@ -320,11 +315,11 @@
 }
 
 gfx::Size V4L2ImageProcessor::input_allocated_size() const {
-  return input_allocated_size_;
+  return input_layout_.coded_size();
 }
 
 gfx::Size V4L2ImageProcessor::output_allocated_size() const {
-  return output_allocated_size_;
+  return output_layout_.coded_size();
 }
 
 bool V4L2ImageProcessor::Process(scoped_refptr<VideoFrame> frame,
@@ -351,9 +346,10 @@
       return false;
   }
 
-  if (output_dmabuf_fds.size() != output_planes_count_) {
-    VLOGF(1) << "wrong number of output fds. Expected " << output_planes_count_
-             << ", actual " << output_dmabuf_fds.size();
+  if (output_dmabuf_fds.size() != output_layout_.num_buffers()) {
+    VLOGF(1) << "wrong number of output fds. Expected "
+             << output_layout_.num_buffers() << ", actual "
+             << output_dmabuf_fds.size();
     return false;
   }
 
@@ -362,14 +358,9 @@
   job_record->output_buffer_index = output_buffer_index;
   job_record->ready_cb = std::move(cb);
 
-  auto layout =
-      VideoFrameLayout::Create(output_format_, output_allocated_size_);
-  if (!layout) {
-    return false;
-  }
   // Create the output frame
   job_record->output_frame = VideoFrame::WrapExternalDmabufs(
-      *layout, gfx::Rect(output_visible_size_), output_visible_size_,
+      output_layout_, gfx::Rect(output_visible_size_), output_visible_size_,
       std::move(output_dmabuf_fds), job_record->input_frame->timestamp());
 
   if (!job_record->output_frame)
@@ -545,7 +536,7 @@
     for (unsigned int i = 0; i < output_buffer_map_.size(); i++) {
       OutputRecord& output_record = output_buffer_map_[i];
       output_record.dmabuf_fds = device_->GetDmabufsForV4L2Buffer(
-          i, output_planes_count_, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+          i, output_layout_.num_buffers(), V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
       if (output_record.dmabuf_fds.empty()) {
         VLOGF(1) << "failed to get fds of output buffer";
         return false;
@@ -702,7 +693,7 @@
     dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
     dqbuf.memory = input_memory_type_;
     dqbuf.m.planes = planes;
-    dqbuf.length = input_planes_count_;
+    dqbuf.length = input_layout_.num_buffers();
     if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
       if (errno == EAGAIN) {
         // EAGAIN if we're just out of buffers to dequeue.
@@ -719,7 +710,6 @@
     free_input_buffers_.push_back(dqbuf.index);
     input_buffer_queued_count_--;
   }
-
   // Dequeue completed output (VIDEO_CAPTURE) buffers, recycle to the free list.
   // Return the finished buffer to the client via the job ready callback.
   while (output_buffer_queued_count_ > 0) {
@@ -729,7 +719,7 @@
     dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
     dqbuf.memory = output_memory_type_;
     dqbuf.m.planes = planes;
-    dqbuf.length = output_planes_count_;
+    dqbuf.length = output_layout_.num_buffers();
     if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
       if (errno == EAGAIN) {
         // EAGAIN if we're just out of buffers to dequeue.
@@ -778,22 +768,22 @@
   qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
   qbuf.memory = input_memory_type_;
   qbuf.m.planes = qbuf_planes;
-  qbuf.length = input_planes_count_;
+  qbuf.length = input_layout_.num_buffers();
 
   std::vector<int> fds;
   if (input_memory_type_ == V4L2_MEMORY_DMABUF) {
     auto& scoped_fds = input_record.frame->DmabufFds();
-    if (scoped_fds.size() != input_planes_count_) {
+    if (scoped_fds.size() != input_layout_.num_buffers()) {
       VLOGF(1) << "Invalid number of planes in the frame";
       return false;
     }
     for (auto& fd : scoped_fds)
       fds.push_back(fd.get());
   }
-  for (size_t i = 0; i < input_planes_count_; ++i) {
+  for (size_t i = 0; i < input_layout_.num_buffers(); ++i) {
     qbuf.m.planes[i].bytesused =
         VideoFrame::PlaneSize(input_record.frame->format(), i,
-                              input_allocated_size_)
+                              input_allocated_size())
             .GetArea();
     qbuf.m.planes[i].length = qbuf.m.planes[i].bytesused;
     switch (input_memory_type_) {
@@ -840,7 +830,7 @@
   qbuf.memory = output_memory_type_;
   if (output_memory_type_ == V4L2_MEMORY_DMABUF) {
     auto& fds = job_record->output_frame->DmabufFds();
-    if (fds.size() != output_planes_count_) {
+    if (fds.size() != output_layout_.num_buffers()) {
       VLOGF(1) << "Invalid number of FDs in output record";
       return false;
     }
@@ -848,7 +838,7 @@
       qbuf_planes[i].m.fd = fds[i].get();
   }
   qbuf.m.planes = qbuf_planes;
-  qbuf.length = output_planes_count_;
+  qbuf.length = output_layout_.num_buffers();
   IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
   output_record.at_device = true;
   output_buffer_queued_count_++;
diff --git a/media/gpu/v4l2/v4l2_image_processor.h b/media/gpu/v4l2/v4l2_image_processor.h
index f300460..20f3479 100644
--- a/media/gpu/v4l2/v4l2_image_processor.h
+++ b/media/gpu/v4l2/v4l2_image_processor.h
@@ -18,8 +18,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread.h"
-#include "media/base/video_frame.h"
-#include "media/base/video_types.h"
+#include "media/base/video_frame_layout.h"
 #include "media/gpu/image_processor.h"
 #include "media/gpu/media_gpu_export.h"
 #include "media/gpu/v4l2/v4l2_device.h"
@@ -69,12 +68,10 @@
       scoped_refptr<V4L2Device> device,
       v4l2_memory input_memory_type,
       v4l2_memory output_memory_type,
-      VideoPixelFormat input_format,
-      VideoPixelFormat output_format,
+      const VideoFrameLayout& input_layout,
+      const VideoFrameLayout& output_layout,
       gfx::Size input_visible_size,
-      gfx::Size input_allocated_size,
       gfx::Size output_visible_size,
-      gfx::Size output_allocated_size,
       size_t num_buffers,
       const base::Closure& error_cb);
 
@@ -118,14 +115,10 @@
   V4L2ImageProcessor(scoped_refptr<V4L2Device> device,
                      v4l2_memory input_memory_type,
                      v4l2_memory output_memory_type,
-                     VideoPixelFormat input_format,
-                     VideoPixelFormat output_format,
+                     const VideoFrameLayout& input_layout,
+                     const VideoFrameLayout& output_layout,
                      gfx::Size input_visible_size,
-                     gfx::Size input_allocated_size,
                      gfx::Size output_visible_size,
-                     gfx::Size output_allocated_size,
-                     size_t input_planes_count,
-                     size_t output_planes_count,
                      size_t num_buffers,
                      const base::Closure& error_cb);
 
@@ -160,22 +153,15 @@
   // callbacks will be invoked.
   void Destroy();
 
-  // Size and format-related members remain constant after initialization.
-  // The visible/allocated sizes of the input frame.
+  // Stores input frame's format, coded_size, buffer and plane layout.
+  const VideoFrameLayout input_layout_;
   const gfx::Size input_visible_size_;
-  const gfx::Size input_allocated_size_;
-
-  // The visible/allocated sizes of the destination frame.
-  const gfx::Size output_visible_size_;
-  const gfx::Size output_allocated_size_;
-
-  const VideoPixelFormat input_format_;
-  const VideoPixelFormat output_format_;
   const v4l2_memory input_memory_type_;
-  const v4l2_memory output_memory_type_;
 
-  const size_t input_planes_count_;
-  const size_t output_planes_count_;
+  // Stores input frame's format, coded_size, buffer and plane layout.
+  const VideoFrameLayout output_layout_;
+  const gfx::Size output_visible_size_;
+  const v4l2_memory output_memory_type_;
 
   // Our original calling task runner for the child thread.
   const scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
diff --git a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
index 348cd9d..112facb 100644
--- a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
@@ -26,6 +26,7 @@
 #include "media/base/media_switches.h"
 #include "media/base/scopedfd_helper.h"
 #include "media/base/unaligned_shared_memory.h"
+#include "media/base/video_frame_layout.h"
 #include "media/base/video_types.h"
 #include "media/gpu/v4l2/v4l2_image_processor.h"
 #include "media/video/h264_parser.h"
@@ -2357,13 +2358,26 @@
       (output_mode_ == Config::OutputMode::ALLOCATE ? V4L2_MEMORY_MMAP
                                                     : V4L2_MEMORY_DMABUF);
 
+  auto input_layout = VideoFrameLayout::Create(
+      V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_),
+      coded_size_);
+  if (!input_layout) {
+    VLOGF(1) << "Invalid input layout";
+    return false;
+  }
+  auto output_layout = VideoFrameLayout::Create(
+      V4L2Device::V4L2PixFmtToVideoPixelFormat(egl_image_format_fourcc_),
+      egl_image_size_);
+  if (!output_layout) {
+    VLOGF(1) << "Invalid output layout";
+    return false;
+  }
+
   // Unretained is safe because |this| owns image processor and there will be
   // no callbacks after processor destroys.
   image_processor_ = V4L2ImageProcessor::Create(
       image_processor_device_, input_memory_type, output_memory_type,
-      V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_),
-      V4L2Device::V4L2PixFmtToVideoPixelFormat(egl_image_format_fourcc_),
-      visible_size_, coded_size_, visible_size_, egl_image_size_,
+      *input_layout, *output_layout, visible_size_, visible_size_,
       output_buffer_map_.size(),
       base::Bind(&V4L2VideoDecodeAccelerator::ImageProcessorError,
                  base::Unretained(this)));
diff --git a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
index f7d33e99..c579f95 100644
--- a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
@@ -26,6 +26,7 @@
 #include "media/base/scopedfd_helper.h"
 #include "media/base/unaligned_shared_memory.h"
 #include "media/base/video_types.h"
+#include "media/base/video_frame_layout.h"
 #include "media/gpu/gpu_video_encode_accelerator_helpers.h"
 #include "media/gpu/v4l2/v4l2_image_processor.h"
 #include "media/video/h264_parser.h"
@@ -209,19 +210,34 @@
       return false;
     }
 
+    auto input_layout = VideoFrameLayout::Create(
+        V4L2Device::V4L2PixFmtToVideoPixelFormat(config.input_format),
+        visible_size_);
+    if (!input_layout) {
+      VLOGF(1) << "Invalid image processor input layout";
+      return false;
+    }
+    auto output_layout = VideoFrameLayout::Create(
+        V4L2Device::V4L2PixFmtToVideoPixelFormat(device_input_format_),
+        input_allocated_size_);
+    if (!output_layout) {
+      VLOGF(1) << "Invalid image processor output layout";
+      return false;
+  }
+
     // Convert from |config.input_format| to |device_input_format_|, keeping the
     // size at |visible_size_| and requiring the output buffers to be of at
     // least |input_allocated_size_|. Unretained is safe because |this| owns
     // image processor and there will be no callbacks after processor destroys.
-    image_processor_ = V4L2ImageProcessor::Create(
-        V4L2Device::Create(), V4L2_MEMORY_USERPTR, V4L2_MEMORY_MMAP,
-        config.input_format, device_input_format_, visible_size_, visible_size_,
-        visible_size_, input_allocated_size_, kImageProcBufferCount,
-        base::Bind(&V4L2VideoEncodeAccelerator::ImageProcessorError,
-                   base::Unretained(this)));
-    if (!image_processor_) {
-      VLOGF(1) << "Failed initializing image processor";
-      return false;
+  image_processor_ = V4L2ImageProcessor::Create(
+      V4L2Device::Create(), V4L2_MEMORY_USERPTR, V4L2_MEMORY_MMAP,
+      *input_layout, *output_layout, visible_size_, visible_size_,
+      kImageProcBufferCount,
+      base::Bind(&V4L2VideoEncodeAccelerator::ImageProcessorError,
+                 base::Unretained(this)));
+  if (!image_processor_) {
+    VLOGF(1) << "Failed initializing image processor";
+    return false;
     }
     // The output of image processor is the input of encoder. Output coded
     // width of processor must be the same as input coded width of encoder.
diff --git a/printing/printed_document.cc b/printing/printed_document.cc
index 5e50a23..78efcb9 100644
--- a/printing/printed_document.cc
+++ b/printing/printed_document.cc
@@ -23,7 +23,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
-#include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "printing/metafile.h"
@@ -47,8 +46,6 @@
 #if defined(OS_WIN)
 void DebugDumpPageTask(const base::string16& doc_name,
                        const PrintedPage* page) {
-  base::AssertBlockingAllowedDeprecated();
-
   DCHECK(PrintedDocument::HasDebugDumpPath());
 
   static constexpr base::FilePath::CharType kExtension[] =
@@ -64,8 +61,6 @@
 #else
 void DebugDumpTask(const base::string16& doc_name,
                    const MetafilePlayer* metafile) {
-  base::AssertBlockingAllowedDeprecated();
-
   DCHECK(PrintedDocument::HasDebugDumpPath());
 
   static constexpr base::FilePath::CharType kExtension[] =
@@ -82,8 +77,6 @@
 void DebugDumpDataTask(const base::string16& doc_name,
                        const base::FilePath::StringType& extension,
                        const base::RefCountedMemory* data) {
-  base::AssertBlockingAllowedDeprecated();
-
   base::FilePath path =
       PrintedDocument::CreateDebugDumpPath(doc_name, extension);
   if (path.empty())
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc
index b9a55753..066f4de 100644
--- a/services/identity/public/cpp/identity_manager.cc
+++ b/services/identity/public/cpp/identity_manager.cc
@@ -207,6 +207,18 @@
   diagnostics_observer_list_.RemoveObserver(observer);
 }
 
+SigninManagerBase* IdentityManager::GetSigninManager() {
+  return signin_manager_;
+}
+
+ProfileOAuth2TokenService* IdentityManager::GetTokenService() {
+  return token_service_;
+}
+
+AccountTrackerService* IdentityManager::GetAccountTrackerService() {
+  return account_tracker_service_;
+}
+
 void IdentityManager::SetPrimaryAccountSynchronouslyForTests(
     const std::string& gaia_id,
     const std::string& email_address,
diff --git a/services/identity/public/cpp/identity_manager.h b/services/identity/public/cpp/identity_manager.h
index 69239c1f..26764b7 100644
--- a/services/identity/public/cpp/identity_manager.h
+++ b/services/identity/public/cpp/identity_manager.h
@@ -46,6 +46,7 @@
 namespace identity {
 
 class PrimaryAccountMutator;
+enum class ClearPrimaryAccountPolicy;
 
 // Gives access to information about the user's Google identities. See
 // ./README.md for detailed documentation.
@@ -265,10 +266,32 @@
   void RemoveDiagnosticsObserver(DiagnosticsObserver* observer);
 
  private:
-  // These clients need to call SetPrimaryAccountSynchronouslyForTests().
-  friend AccountInfo SetPrimaryAccount(SigninManagerBase* signin_manager,
-                                       IdentityManager* identity_manager,
+  // These test helpers need to use some of the private methods below.
+  friend AccountInfo SetPrimaryAccount(IdentityManager* identity_manager,
                                        const std::string& email);
+  friend void SetRefreshTokenForPrimaryAccount(
+      IdentityManager* identity_manager);
+  friend void SetInvalidRefreshTokenForPrimaryAccount(
+      IdentityManager* identity_manager);
+  friend void RemoveRefreshTokenForPrimaryAccount(
+      IdentityManager* identity_manager);
+  friend AccountInfo MakePrimaryAccountAvailable(
+      IdentityManager* identity_manager,
+      const std::string& email);
+  friend void ClearPrimaryAccount(IdentityManager* identity_manager,
+                                  ClearPrimaryAccountPolicy policy);
+  friend AccountInfo MakeAccountAvailable(IdentityManager* identity_manager,
+                                          const std::string& email);
+  friend void SetRefreshTokenForAccount(IdentityManager* identity_manager,
+                                        const std::string& account_id);
+  friend void SetInvalidRefreshTokenForAccount(
+      IdentityManager* identity_manager,
+      const std::string& account_id);
+  friend void RemoveRefreshTokenForAccount(IdentityManager* identity_manager,
+                                           const std::string& account_id);
+  friend void UpdateAccountInfoForAccount(IdentityManager* identity_manager,
+                                          AccountInfo account_info);
+
   friend MultiProfileDownloadNotificationTest;
   friend file_manager::MultiProfileFilesAppBrowserTest;
 
@@ -278,6 +301,11 @@
   friend chromeos::ChromeSessionManager;
   friend chromeos::UserSessionManager;
 
+  // Private getters used for testing only (i.e. see identity_test_utils.h).
+  SigninManagerBase* GetSigninManager();
+  ProfileOAuth2TokenService* GetTokenService();
+  AccountTrackerService* GetAccountTrackerService();
+
   // Sets the primary account info synchronously with both the IdentityManager
   // and its backing SigninManager/ProfileOAuth2TokenService instances.
   // Prefer using the methods in identity_test_{environment, utils}.h to using
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc
index dc5c2516..ec76064d 100644
--- a/services/identity/public/cpp/identity_manager_unittest.cc
+++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -514,10 +514,10 @@
     // Ensure primary and secondary emails are set up with refresh tokens. Some
     // tests may do this externally for the primary account.
     if (!identity_manager()->HasPrimaryAccountWithRefreshToken())
-      SetRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+      SetRefreshTokenForPrimaryAccount(identity_manager());
     EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken());
-    AccountInfo secondary_account_info = MakeAccountAvailable(
-        account_tracker(), token_service(), identity_manager(), kTestEmail2);
+    AccountInfo secondary_account_info =
+        MakeAccountAvailable(identity_manager(), kTestEmail2);
     EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken(
         secondary_account_info.account_id));
 
@@ -693,7 +693,7 @@
       SigninManagerSetup::kWithAuthenticatedAccout);
 
   // Set primary account to have authentication error.
-  SetRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  SetRefreshTokenForPrimaryAccount(identity_manager());
   token_service()->UpdateAuthErrorForTesting(
       identity_manager()->GetPrimaryAccountId(),
       GoogleServiceAuthError(
@@ -719,8 +719,8 @@
 
   // Add a secondary account to verify that its refresh token survives the
   // call to ClearPrimaryAccount(...) below.
-  AccountInfo secondary_account_info = MakeAccountAvailable(
-      account_tracker(), token_service(), identity_manager(), kTestEmail2);
+  AccountInfo secondary_account_info =
+      MakeAccountAvailable(identity_manager(), kTestEmail2);
   EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken(
       secondary_account_info.account_id));
 
@@ -850,7 +850,7 @@
 
   // Add a refresh token for the primary account and check that it shows up in
   // GetAccountsWithRefreshTokens().
-  SetRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  SetRefreshTokenForPrimaryAccount(identity_manager());
 
   std::vector<AccountInfo> accounts_after_update =
       identity_manager()->GetAccountsWithRefreshTokens();
@@ -861,7 +861,7 @@
   EXPECT_EQ(accounts_after_update[0].email, kTestEmail);
 
   // Update the token and check that it doesn't change the state (or blow up).
-  SetRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  SetRefreshTokenForPrimaryAccount(identity_manager());
 
   std::vector<AccountInfo> accounts_after_second_update =
       identity_manager()->GetAccountsWithRefreshTokens();
@@ -873,7 +873,7 @@
 
   // Remove the token for the primary account and check that this is likewise
   // reflected.
-  RemoveRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  RemoveRefreshTokenForPrimaryAccount(identity_manager());
 
   EXPECT_TRUE(identity_manager()->GetAccountsWithRefreshTokens().empty());
 }
@@ -890,14 +890,14 @@
 
   // Add a refresh token for the primary account and check that it affects this
   // state.
-  SetRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  SetRefreshTokenForPrimaryAccount(identity_manager());
 
   EXPECT_TRUE(
       identity_manager()->HasAccountWithRefreshToken(account_info.account_id));
   EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken());
 
   // Update the token and check that it doesn't change the state (or blow up).
-  SetRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  SetRefreshTokenForPrimaryAccount(identity_manager());
 
   EXPECT_TRUE(
       identity_manager()->HasAccountWithRefreshToken(account_info.account_id));
@@ -905,7 +905,7 @@
 
   // Remove the token for the primary account and check that this is likewise
   // reflected.
-  RemoveRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  RemoveRefreshTokenForPrimaryAccount(identity_manager());
 
   EXPECT_FALSE(
       identity_manager()->HasAccountWithRefreshToken(account_info.account_id));
@@ -919,7 +919,7 @@
 
   // Add a refresh token for the primary account and sanity-check that it shows
   // up in GetAccountsWithRefreshTokens().
-  SetRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  SetRefreshTokenForPrimaryAccount(identity_manager());
 
   std::vector<AccountInfo> accounts_after_update =
       identity_manager()->GetAccountsWithRefreshTokens();
@@ -950,7 +950,7 @@
       identity_manager()->HasAccountWithRefreshToken(account_info.account_id));
   EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken());
 
-  SetRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  SetRefreshTokenForPrimaryAccount(identity_manager());
 
   EXPECT_TRUE(
       identity_manager()->HasAccountWithRefreshToken(account_info.account_id));
@@ -974,7 +974,7 @@
   account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2);
   std::string account_id2 =
       account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2).account_id;
-  SetRefreshTokenForAccount(token_service(), identity_manager(), account_id2);
+  SetRefreshTokenForAccount(identity_manager(), account_id2);
 
   std::vector<AccountInfo> accounts_after_update =
       identity_manager()->GetAccountsWithRefreshTokens();
@@ -989,7 +989,7 @@
   account_tracker()->SeedAccountInfo(kTestGaiaId3, kTestEmail3);
   std::string account_id3 =
       account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId3).account_id;
-  SetRefreshTokenForAccount(token_service(), identity_manager(), account_id3);
+  SetRefreshTokenForAccount(identity_manager(), account_id3);
 
   std::vector<AccountInfo> accounts_after_second_update =
       identity_manager()->GetAccountsWithRefreshTokens();
@@ -1006,8 +1006,7 @@
   }
 
   // Remove the token for account2 and check that account3 is still present.
-  RemoveRefreshTokenForAccount(token_service(), identity_manager(),
-                               account_id2);
+  RemoveRefreshTokenForAccount(identity_manager(), account_id2);
 
   std::vector<AccountInfo> accounts_after_third_update =
       identity_manager()->GetAccountsWithRefreshTokens();
@@ -1027,7 +1026,7 @@
   account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2);
   std::string account_id2 =
       account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2).account_id;
-  SetRefreshTokenForAccount(token_service(), identity_manager(), account_id2);
+  SetRefreshTokenForAccount(identity_manager(), account_id2);
 
   EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken());
 
@@ -1036,13 +1035,12 @@
   account_tracker()->SeedAccountInfo(kTestGaiaId3, kTestEmail3);
   std::string account_id3 =
       account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId3).account_id;
-  SetRefreshTokenForAccount(token_service(), identity_manager(), account_id3);
+  SetRefreshTokenForAccount(identity_manager(), account_id3);
 
   EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken());
 
   // Removing the token for account2 should have no effect.
-  RemoveRefreshTokenForAccount(token_service(), identity_manager(),
-                               account_id2);
+  RemoveRefreshTokenForAccount(identity_manager(), account_id2);
 
   EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken());
 }
@@ -1059,7 +1057,7 @@
 
   // Add a refresh token for account_info2 and check that this is reflected by
   // HasAccountWithRefreshToken(.account_id).
-  SetRefreshTokenForAccount(token_service(), identity_manager(), account_id2);
+  SetRefreshTokenForAccount(identity_manager(), account_id2);
 
   EXPECT_TRUE(
       identity_manager()->HasAccountWithRefreshToken(account_info2.account_id));
@@ -1075,7 +1073,7 @@
   EXPECT_FALSE(
       identity_manager()->HasAccountWithRefreshToken(account_info3.account_id));
 
-  SetRefreshTokenForAccount(token_service(), identity_manager(), account_id3);
+  SetRefreshTokenForAccount(identity_manager(), account_id3);
 
   EXPECT_TRUE(
       identity_manager()->HasAccountWithRefreshToken(account_info2.account_id));
@@ -1083,8 +1081,7 @@
       identity_manager()->HasAccountWithRefreshToken(account_info3.account_id));
 
   // Remove the token for account2.
-  RemoveRefreshTokenForAccount(token_service(), identity_manager(),
-                               account_id2);
+  RemoveRefreshTokenForAccount(identity_manager(), account_id2);
 
   EXPECT_FALSE(
       identity_manager()->HasAccountWithRefreshToken(account_info2.account_id));
@@ -1102,7 +1099,7 @@
   account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2);
   std::string account_id2 =
       account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2).account_id;
-  SetRefreshTokenForAccount(token_service(), identity_manager(), account_id2);
+  SetRefreshTokenForAccount(identity_manager(), account_id2);
 
   std::vector<AccountInfo> accounts_after_update =
       identity_manager()->GetAccountsWithRefreshTokens();
@@ -1118,7 +1115,7 @@
   // also shows up in GetAccountsWithRefreshTokens().
   std::string primary_account_id =
       signin_manager()->GetAuthenticatedAccountId();
-  SetRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  SetRefreshTokenForPrimaryAccount(identity_manager());
 
   std::vector<AccountInfo> accounts_after_second_update =
       identity_manager()->GetAccountsWithRefreshTokens();
@@ -1138,7 +1135,7 @@
 
   // Remove the token for the primary account and check that account2 is still
   // present.
-  RemoveRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  RemoveRefreshTokenForPrimaryAccount(identity_manager());
 
   std::vector<AccountInfo> accounts_after_third_update =
       identity_manager()->GetAccountsWithRefreshTokens();
@@ -1161,7 +1158,7 @@
   account_tracker()->SeedAccountInfo(kTestGaiaId2, kTestEmail2);
   std::string account_id2 =
       account_tracker()->FindAccountInfoByGaiaId(kTestGaiaId2).account_id;
-  SetRefreshTokenForAccount(token_service(), identity_manager(), account_id2);
+  SetRefreshTokenForAccount(identity_manager(), account_id2);
 
   EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken());
 
@@ -1169,20 +1166,19 @@
   // *does* impact the stsate of HasPrimaryAccountWithRefreshToken().
   std::string primary_account_id =
       signin_manager()->GetAuthenticatedAccountId();
-  SetRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  SetRefreshTokenForPrimaryAccount(identity_manager());
 
   EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken());
 
   // Remove the token for the secondary account and check that this doesn't flip
   // the state.
-  RemoveRefreshTokenForAccount(token_service(), identity_manager(),
-                               account_id2);
+  RemoveRefreshTokenForAccount(identity_manager(), account_id2);
 
   EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken());
 
   // Remove the token for the primary account and check that this flips the
   // state.
-  RemoveRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  RemoveRefreshTokenForPrimaryAccount(identity_manager());
 
   EXPECT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken());
 }
@@ -1206,7 +1202,7 @@
 
   // Add a refresh token for account_info2 and check that this is reflected by
   // HasAccountWithRefreshToken(.account_id).
-  SetRefreshTokenForAccount(token_service(), identity_manager(), account_id2);
+  SetRefreshTokenForAccount(identity_manager(), account_id2);
 
   EXPECT_FALSE(identity_manager()->HasAccountWithRefreshToken(
       primary_account_info.account_id));
@@ -1214,7 +1210,7 @@
       identity_manager()->HasAccountWithRefreshToken(account_info2.account_id));
 
   // Go through the same process for the primary account.
-  SetRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  SetRefreshTokenForPrimaryAccount(identity_manager());
 
   EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken(
       primary_account_info.account_id));
@@ -1222,8 +1218,7 @@
       identity_manager()->HasAccountWithRefreshToken(account_info2.account_id));
 
   // Remove the token for account2.
-  RemoveRefreshTokenForAccount(token_service(), identity_manager(),
-                               account_id2);
+  RemoveRefreshTokenForAccount(identity_manager(), account_id2);
 
   EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken(
       primary_account_info.account_id));
@@ -1245,7 +1240,7 @@
       identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState(
           primary_account_id));
 
-  SetRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  SetRefreshTokenForPrimaryAccount(identity_manager());
   EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
             identity_manager()->GetErrorStateOfRefreshTokenForAccount(
                 primary_account_id));
@@ -1266,7 +1261,7 @@
       identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState(
           account_id2));
 
-  SetRefreshTokenForAccount(token_service(), identity_manager(), account_id2);
+  SetRefreshTokenForAccount(identity_manager(), account_id2);
   EXPECT_EQ(
       GoogleServiceAuthError::AuthErrorNone(),
       identity_manager()->GetErrorStateOfRefreshTokenForAccount(account_id2));
@@ -1326,8 +1321,7 @@
 
   // Remove the token for account2 and check that it goes back to having no
   // error.
-  RemoveRefreshTokenForAccount(token_service(), identity_manager(),
-                               account_id2);
+  RemoveRefreshTokenForAccount(identity_manager(), account_id2);
   EXPECT_EQ(
       GoogleServiceAuthError::AuthErrorNone(),
       identity_manager()->GetErrorStateOfRefreshTokenForAccount(account_id2));
@@ -1576,7 +1570,7 @@
        CallbackSentOnPrimaryAccountRefreshTokenUpdateWithValidToken) {
   std::string account_id = signin_manager()->GetAuthenticatedAccountId();
 
-  SetRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  SetRefreshTokenForPrimaryAccount(identity_manager());
 
   AccountInfo account_info =
       identity_manager_observer()
@@ -1592,7 +1586,7 @@
        CallbackSentOnPrimaryAccountRefreshTokenUpdateWithInvalidToken) {
   std::string account_id = signin_manager()->GetAuthenticatedAccountId();
 
-  SetInvalidRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  SetInvalidRefreshTokenForPrimaryAccount(identity_manager());
 
   AccountInfo account_info =
       identity_manager_observer()
@@ -1607,9 +1601,9 @@
 TEST_F(IdentityManagerTest, CallbackSentOnPrimaryAccountRefreshTokenRemoval) {
   std::string account_id = signin_manager()->GetAuthenticatedAccountId();
 
-  SetRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  SetRefreshTokenForPrimaryAccount(identity_manager());
 
-  RemoveRefreshTokenForPrimaryAccount(token_service(), identity_manager());
+  RemoveRefreshTokenForPrimaryAccount(identity_manager());
 
   EXPECT_EQ(account_id, identity_manager_observer()
                             ->account_from_refresh_token_removed_callback());
@@ -1617,8 +1611,8 @@
 
 TEST_F(IdentityManagerTest,
        CallbackSentOnSecondaryAccountRefreshTokenUpdateWithValidToken) {
-  AccountInfo expected_account_info = MakeAccountAvailable(
-      account_tracker(), token_service(), identity_manager(), kTestEmail2);
+  AccountInfo expected_account_info =
+      MakeAccountAvailable(identity_manager(), kTestEmail2);
   EXPECT_EQ(kTestEmail2, expected_account_info.email);
 
   AccountInfo account_info =
@@ -1634,11 +1628,11 @@
 
 TEST_F(IdentityManagerTest,
        CallbackSentOnSecondaryAccountRefreshTokenUpdateWithInvalidToken) {
-  AccountInfo expected_account_info = MakeAccountAvailable(
-      account_tracker(), token_service(), identity_manager(), kTestEmail2);
+  AccountInfo expected_account_info =
+      MakeAccountAvailable(identity_manager(), kTestEmail2);
   EXPECT_EQ(kTestEmail2, expected_account_info.email);
 
-  SetInvalidRefreshTokenForAccount(token_service(), identity_manager(),
+  SetInvalidRefreshTokenForAccount(identity_manager(),
                                    expected_account_info.account_id);
 
   AccountInfo account_info =
@@ -1653,11 +1647,11 @@
 }
 
 TEST_F(IdentityManagerTest, CallbackSentOnSecondaryAccountRefreshTokenRemoval) {
-  AccountInfo expected_account_info = MakeAccountAvailable(
-      account_tracker(), token_service(), identity_manager(), kTestEmail2);
+  AccountInfo expected_account_info =
+      MakeAccountAvailable(identity_manager(), kTestEmail2);
   EXPECT_EQ(kTestEmail2, expected_account_info.email);
 
-  RemoveRefreshTokenForAccount(token_service(), identity_manager(),
+  RemoveRefreshTokenForAccount(identity_manager(),
                                expected_account_info.account_id);
 
   EXPECT_EQ(expected_account_info.account_id,
@@ -1675,8 +1669,8 @@
   signin_manager()->ForceSignOut();
   run_loop.Run();
 
-  AccountInfo expected_account_info = MakeAccountAvailable(
-      account_tracker(), token_service(), identity_manager(), kTestEmail2);
+  AccountInfo expected_account_info =
+      MakeAccountAvailable(identity_manager(), kTestEmail2);
   EXPECT_EQ(kTestEmail2, expected_account_info.email);
 
   AccountInfo account_info =
@@ -1699,11 +1693,11 @@
   signin_manager()->ForceSignOut();
   run_loop.Run();
 
-  AccountInfo expected_account_info = MakeAccountAvailable(
-      account_tracker(), token_service(), identity_manager(), kTestEmail2);
+  AccountInfo expected_account_info =
+      MakeAccountAvailable(identity_manager(), kTestEmail2);
   EXPECT_EQ(kTestEmail2, expected_account_info.email);
 
-  SetInvalidRefreshTokenForAccount(token_service(), identity_manager(),
+  SetInvalidRefreshTokenForAccount(identity_manager(),
                                    expected_account_info.account_id);
 
   AccountInfo account_info =
@@ -1725,11 +1719,11 @@
   signin_manager()->ForceSignOut();
   run_loop.Run();
 
-  AccountInfo expected_account_info = MakeAccountAvailable(
-      account_tracker(), token_service(), identity_manager(), kTestEmail2);
+  AccountInfo expected_account_info =
+      MakeAccountAvailable(identity_manager(), kTestEmail2);
   EXPECT_EQ(kTestEmail2, expected_account_info.email);
 
-  RemoveRefreshTokenForAccount(token_service(), identity_manager(),
+  RemoveRefreshTokenForAccount(identity_manager(),
                                expected_account_info.account_id);
 
   EXPECT_EQ(expected_account_info.account_id,
diff --git a/services/identity/public/cpp/identity_test_environment.cc b/services/identity/public/cpp/identity_test_environment.cc
index e75e1c0..8c2a95e 100644
--- a/services/identity/public/cpp/identity_test_environment.cc
+++ b/services/identity/public/cpp/identity_test_environment.cc
@@ -207,58 +207,50 @@
 
 AccountInfo IdentityTestEnvironment::SetPrimaryAccount(
     const std::string& email) {
-  return identity::SetPrimaryAccount(signin_manager_, identity_manager(),
-                                     email);
+  return identity::SetPrimaryAccount(identity_manager(), email);
 }
 
 void IdentityTestEnvironment::SetRefreshTokenForPrimaryAccount() {
-  identity::SetRefreshTokenForPrimaryAccount(token_service_,
-                                             identity_manager());
+  identity::SetRefreshTokenForPrimaryAccount(identity_manager());
 }
 
 void IdentityTestEnvironment::SetInvalidRefreshTokenForPrimaryAccount() {
-  identity::SetInvalidRefreshTokenForPrimaryAccount(token_service_,
-                                                    identity_manager());
+  identity::SetInvalidRefreshTokenForPrimaryAccount(identity_manager());
 }
 
 void IdentityTestEnvironment::RemoveRefreshTokenForPrimaryAccount() {
-  identity::RemoveRefreshTokenForPrimaryAccount(token_service_,
-                                                identity_manager());
+  identity::RemoveRefreshTokenForPrimaryAccount(identity_manager());
 }
 
 AccountInfo IdentityTestEnvironment::MakePrimaryAccountAvailable(
     const std::string& email) {
-  return identity::MakePrimaryAccountAvailable(signin_manager_, token_service_,
-                                               identity_manager(), email);
+  return identity::MakePrimaryAccountAvailable(identity_manager(), email);
 }
 
 void IdentityTestEnvironment::ClearPrimaryAccount(
     ClearPrimaryAccountPolicy policy) {
-  identity::ClearPrimaryAccount(signin_manager_, identity_manager(), policy);
+  identity::ClearPrimaryAccount(identity_manager(), policy);
 }
 
 AccountInfo IdentityTestEnvironment::MakeAccountAvailable(
     const std::string& email) {
-  return identity::MakeAccountAvailable(
-      account_tracker_service_, token_service_, identity_manager(), email);
+  return identity::MakeAccountAvailable(identity_manager(), email);
 }
 
 void IdentityTestEnvironment::SetRefreshTokenForAccount(
     const std::string& account_id) {
-  return identity::SetRefreshTokenForAccount(token_service_, identity_manager(),
-                                             account_id);
+  return identity::SetRefreshTokenForAccount(identity_manager(), account_id);
 }
 
 void IdentityTestEnvironment::SetInvalidRefreshTokenForAccount(
     const std::string& account_id) {
-  return identity::SetInvalidRefreshTokenForAccount(
-      token_service_, identity_manager(), account_id);
+  return identity::SetInvalidRefreshTokenForAccount(identity_manager(),
+                                                    account_id);
 }
 
 void IdentityTestEnvironment::RemoveRefreshTokenForAccount(
     const std::string& account_id) {
-  return identity::RemoveRefreshTokenForAccount(token_service_,
-                                                identity_manager(), account_id);
+  return identity::RemoveRefreshTokenForAccount(identity_manager(), account_id);
 }
 
 void IdentityTestEnvironment::SetCookieAccounts(
@@ -407,7 +399,7 @@
 
 void IdentityTestEnvironment::UpdateAccountInfoForAccount(
     AccountInfo account_info) {
-  identity::UpdateAccountInfoForAccount(account_tracker_service_, account_info);
+  identity::UpdateAccountInfoForAccount(identity_manager(), account_info);
 }
 
 }  // namespace identity
diff --git a/services/identity/public/cpp/identity_test_environment.h b/services/identity/public/cpp/identity_test_environment.h
index 86892465..ac4e0fe 100644
--- a/services/identity/public/cpp/identity_test_environment.h
+++ b/services/identity/public/cpp/identity_test_environment.h
@@ -18,6 +18,14 @@
 
 namespace identity {
 
+namespace {
+#if defined(OS_CHROMEOS)
+using SigninManagerForTest = FakeSigninManagerBase;
+#else
+using SigninManagerForTest = FakeSigninManager;
+#endif  // OS_CHROMEOS
+}
+
 // Internal class that creates and owns dependencies of IdentityManager
 // when those dependencies are not passed in externally.
 class IdentityManagerDependenciesOwner;
@@ -31,12 +39,6 @@
 // base::test::ScopedTaskEnvironment instance variable to fulfill this
 // requirement.
 class IdentityTestEnvironment : public IdentityManager::DiagnosticsObserver {
-#if defined(OS_CHROMEOS)
-  using SigninManagerForTest = FakeSigninManagerBase;
-#else
-  using SigninManagerForTest = FakeSigninManager;
-#endif  // OS_CHROMEOS
-
  public:
   // Preferred constructor: constructs an IdentityManager object and its
   // dependencies internally. Cannot be used if the client of this class
diff --git a/services/identity/public/cpp/identity_test_utils.cc b/services/identity/public/cpp/identity_test_utils.cc
index 8d2a32f..10e0f59 100644
--- a/services/identity/public/cpp/identity_test_utils.cc
+++ b/services/identity/public/cpp/identity_test_utils.cc
@@ -8,7 +8,6 @@
 #include "base/strings/string_split.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_signin_manager.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "services/identity/public/cpp/identity_manager.h"
 
@@ -127,11 +126,13 @@
 
 }  // namespace
 
-AccountInfo SetPrimaryAccount(SigninManagerBase* signin_manager,
-                              IdentityManager* identity_manager,
+AccountInfo SetPrimaryAccount(IdentityManager* identity_manager,
                               const std::string& email) {
-  DCHECK(!signin_manager->IsAuthenticated());
   DCHECK(!identity_manager->HasPrimaryAccount());
+
+  SigninManagerBase* signin_manager = identity_manager->GetSigninManager();
+  DCHECK(!signin_manager->IsAuthenticated());
+
   std::string gaia_id = "gaia_id_for_" + email;
 
 #if defined(OS_CHROMEOS)
@@ -168,48 +169,41 @@
   return identity_manager->GetPrimaryAccountInfo();
 }
 
-void SetRefreshTokenForPrimaryAccount(ProfileOAuth2TokenService* token_service,
-                                      IdentityManager* identity_manager) {
+void SetRefreshTokenForPrimaryAccount(IdentityManager* identity_manager) {
   DCHECK(identity_manager->HasPrimaryAccount());
   std::string account_id = identity_manager->GetPrimaryAccountId();
 
   std::string refresh_token = "refresh_token_for_" + account_id;
-  SetRefreshTokenForAccount(token_service, identity_manager, account_id);
+  SetRefreshTokenForAccount(identity_manager, account_id);
 }
 
 void SetInvalidRefreshTokenForPrimaryAccount(
-    ProfileOAuth2TokenService* token_service,
     IdentityManager* identity_manager) {
   DCHECK(identity_manager->HasPrimaryAccount());
   std::string account_id = identity_manager->GetPrimaryAccountId();
 
-  SetInvalidRefreshTokenForAccount(token_service, identity_manager, account_id);
+  SetInvalidRefreshTokenForAccount(identity_manager, account_id);
 }
 
 void RemoveRefreshTokenForPrimaryAccount(
-    ProfileOAuth2TokenService* token_service,
     IdentityManager* identity_manager) {
   if (!identity_manager->HasPrimaryAccount())
     return;
 
   std::string account_id = identity_manager->GetPrimaryAccountId();
 
-  RemoveRefreshTokenForAccount(token_service, identity_manager, account_id);
+  RemoveRefreshTokenForAccount(identity_manager, account_id);
 }
 
 AccountInfo MakePrimaryAccountAvailable(
-    SigninManagerBase* signin_manager,
-    ProfileOAuth2TokenService* token_service,
     IdentityManager* identity_manager,
     const std::string& email) {
-  AccountInfo account_info =
-      SetPrimaryAccount(signin_manager, identity_manager, email);
-  SetRefreshTokenForPrimaryAccount(token_service, identity_manager);
+  AccountInfo account_info = SetPrimaryAccount(identity_manager, email);
+  SetRefreshTokenForPrimaryAccount(identity_manager);
   return account_info;
 }
 
-void ClearPrimaryAccount(SigninManagerBase* signin_manager,
-                         IdentityManager* identity_manager,
+void ClearPrimaryAccount(IdentityManager* identity_manager,
                          ClearPrimaryAccountPolicy policy) {
 #if defined(OS_CHROMEOS)
   // TODO(blundell): If we ever need this functionality on ChromeOS (which seems
@@ -225,8 +219,8 @@
       identity_manager, run_loop.QuitClosure(),
       IdentityManagerEvent::PRIMARY_ACCOUNT_CLEARED);
 
-  SigninManager* real_signin_manager =
-      SigninManager::FromSigninManagerBase(signin_manager);
+  SigninManager* real_signin_manager = SigninManager::FromSigninManagerBase(
+      identity_manager->GetSigninManager());
   signin_metrics::ProfileSignout signout_source_metric =
       signin_metrics::SIGNOUT_TEST;
   signin_metrics::SignoutDelete signout_delete_metric =
@@ -251,10 +245,12 @@
 #endif
 }
 
-AccountInfo MakeAccountAvailable(AccountTrackerService* account_tracker_service,
-                                 ProfileOAuth2TokenService* token_service,
-                                 IdentityManager* identity_manager,
+AccountInfo MakeAccountAvailable(IdentityManager* identity_manager,
                                  const std::string& email) {
+  AccountTrackerService* account_tracker_service =
+      identity_manager->GetAccountTrackerService();
+
+  DCHECK(account_tracker_service);
   DCHECK(account_tracker_service->FindAccountInfoByEmail(email).IsEmpty());
 
   std::string gaia_id = "gaia_id_for_" + email;
@@ -264,30 +260,26 @@
       account_tracker_service->FindAccountInfoByEmail(email);
   DCHECK(!account_info.account_id.empty());
 
-  SetRefreshTokenForAccount(token_service, identity_manager,
-                            account_info.account_id);
+  SetRefreshTokenForAccount(identity_manager, account_info.account_id);
 
   return account_info;
 }
 
-void SetRefreshTokenForAccount(ProfileOAuth2TokenService* token_service,
-                               IdentityManager* identity_manager,
+void SetRefreshTokenForAccount(IdentityManager* identity_manager,
                                const std::string& account_id) {
   std::string refresh_token = "refresh_token_for_" + account_id;
-  UpdateRefreshTokenForAccount(token_service, identity_manager, account_id,
-                               refresh_token);
+  UpdateRefreshTokenForAccount(identity_manager->GetTokenService(),
+                               identity_manager, account_id, refresh_token);
 }
 
-void SetInvalidRefreshTokenForAccount(ProfileOAuth2TokenService* token_service,
-                                      IdentityManager* identity_manager,
+void SetInvalidRefreshTokenForAccount(IdentityManager* identity_manager,
                                       const std::string& account_id) {
   UpdateRefreshTokenForAccount(
-      token_service, identity_manager, account_id,
+      identity_manager->GetTokenService(), identity_manager, account_id,
       OAuth2TokenServiceDelegate::kInvalidRefreshToken);
 }
 
-void RemoveRefreshTokenForAccount(ProfileOAuth2TokenService* token_service,
-                                  IdentityManager* identity_manager,
+void RemoveRefreshTokenForAccount(IdentityManager* identity_manager,
                                   const std::string& account_id) {
   if (!identity_manager->HasAccountWithRefreshToken(account_id))
     return;
@@ -297,7 +289,7 @@
       identity_manager, run_loop.QuitClosure(),
       IdentityManagerEvent::REFRESH_TOKEN_REMOVED);
 
-  token_service->RevokeCredentials(account_id);
+  identity_manager->GetTokenService()->RevokeCredentials(account_id);
 
   run_loop.Run();
 }
@@ -326,9 +318,14 @@
   run_loop.Run();
 }
 
-void UpdateAccountInfoForAccount(AccountTrackerService* account_tracker_service,
+void UpdateAccountInfoForAccount(IdentityManager* identity_manager,
                                  AccountInfo account_info) {
   // Make sure the account being updated is a known account.
+
+  AccountTrackerService* account_tracker_service =
+      identity_manager->GetAccountTrackerService();
+
+  DCHECK(account_tracker_service);
   DCHECK(!account_tracker_service->GetAccountInfo(account_info.account_id)
               .account_id.empty());
 
diff --git a/services/identity/public/cpp/identity_test_utils.h b/services/identity/public/cpp/identity_test_utils.h
index 1617750..d6bab00d 100644
--- a/services/identity/public/cpp/identity_test_utils.h
+++ b/services/identity/public/cpp/identity_test_utils.h
@@ -10,18 +10,7 @@
 #include "build/build_config.h"
 #include "components/signin/core/browser/account_info.h"
 
-class AccountTrackerService;
 class FakeGaiaCookieManagerService;
-class FakeSigninManagerBase;
-class FakeSigninManager;
-class ProfileOAuth2TokenService;
-class SigninManagerBase;
-
-#if defined(OS_CHROMEOS)
-using SigninManagerForTest = FakeSigninManagerBase;
-#else
-using SigninManagerForTest = FakeSigninManager;
-#endif  // OS_CHROMEOS
 
 // Test-related utilities that don't fit in either IdentityTestEnvironment or
 // IdentityManager itself. NOTE: Using these utilities directly is discouraged,
@@ -57,28 +46,24 @@
 // SigninManager callbacks for signin success. Blocks until the primary account
 // is set. Returns the AccountInfo of the newly-set account.
 // NOTE: See disclaimer at top of file re: direct usage.
-AccountInfo SetPrimaryAccount(SigninManagerBase* signin_manager,
-                              IdentityManager* identity_manager,
+AccountInfo SetPrimaryAccount(IdentityManager* identity_manager,
                               const std::string& email);
 
 // Sets a refresh token for the primary account (which must already be set).
 // Blocks until the refresh token is set.
 // NOTE: See disclaimer at top of file re: direct usage.
-void SetRefreshTokenForPrimaryAccount(ProfileOAuth2TokenService* token_service,
-                                      IdentityManager* identity_manager);
+void SetRefreshTokenForPrimaryAccount(IdentityManager* identity_manager);
 
 // Sets a special invalid refresh token for the primary account (which must
 // already be set). Blocks until the refresh token is set.
 // NOTE: See disclaimer at top of file re: direct usage.
 void SetInvalidRefreshTokenForPrimaryAccount(
-    ProfileOAuth2TokenService* token_service,
     IdentityManager* identity_manager);
 
 // Removes any refresh token for the primary account, if present. Blocks until
 // the refresh token is removed.
 // NOTE: See disclaimer at top of file re: direct usage.
 void RemoveRefreshTokenForPrimaryAccount(
-    ProfileOAuth2TokenService* token_service,
     IdentityManager* identity_manager);
 
 // Makes the primary account (which must not already be set) available for the
@@ -89,8 +74,6 @@
 // newly-available account.
 // NOTE: See disclaimer at top of file re: direct usage.
 AccountInfo MakePrimaryAccountAvailable(
-    SigninManagerBase* signin_manager,
-    ProfileOAuth2TokenService* token_service,
     IdentityManager* identity_manager,
     const std::string& email);
 
@@ -100,7 +83,6 @@
 // until the primary account is cleared.
 // NOTE: See disclaimer at top of file re: direct usage.
 void ClearPrimaryAccount(
-    SigninManagerBase* signin_manager,
     IdentityManager* identity_manager,
     ClearPrimaryAccountPolicy policy = ClearPrimaryAccountPolicy::DEFAULT);
 
@@ -109,31 +91,26 @@
 // until the account is available. Returns the AccountInfo of the
 // newly-available account.
 // NOTE: See disclaimer at top of file re: direct usage.
-AccountInfo MakeAccountAvailable(AccountTrackerService* account_tracker_service,
-                                 ProfileOAuth2TokenService* token_service,
-                                 IdentityManager* identity_manager,
+AccountInfo MakeAccountAvailable(IdentityManager* identity_manager,
                                  const std::string& email);
 
 // Sets a refresh token for the given account (which must already be available).
 // Blocks until the refresh token is set.
 // NOTE: See disclaimer at top of file re: direct usage.
-void SetRefreshTokenForAccount(ProfileOAuth2TokenService* token_service,
-                               IdentityManager* identity_manager,
+void SetRefreshTokenForAccount(IdentityManager* identity_manager,
                                const std::string& account_id);
 
 // Sets a special invalid refresh token for the given account (which must
 // already be available). Blocks until the refresh token is set.
 // NOTE: See disclaimer at top of file re: direct usage.
-void SetInvalidRefreshTokenForAccount(ProfileOAuth2TokenService* token_service,
-                                      IdentityManager* identity_manager,
+void SetInvalidRefreshTokenForAccount(IdentityManager* identity_manager,
                                       const std::string& account_id);
 
 // Removes any refresh token that is present for the given account. Blocks until
 // the refresh token is removed. Is a no-op if no refresh token is present for
 // the given account.
 // NOTE: See disclaimer at top of file re: direct usage.
-void RemoveRefreshTokenForAccount(ProfileOAuth2TokenService* token_service,
-                                  IdentityManager* identity_manager,
+void RemoveRefreshTokenForAccount(IdentityManager* identity_manager,
                                   const std::string& account_id);
 
 // Puts the given accounts into the Gaia cookie, replacing any previous
@@ -145,7 +122,7 @@
 
 // Updates the info for |account_info.account_id|, which must be a known
 // account.
-void UpdateAccountInfoForAccount(AccountTrackerService* account_tracker_service,
+void UpdateAccountInfoForAccount(IdentityManager* identity_manager,
                                  AccountInfo account_info);
 
 }  // namespace identity
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc
index de0469f..747ef9e 100644
--- a/services/network/public/cpp/features.cc
+++ b/services/network/public/cpp/features.cc
@@ -19,7 +19,7 @@
                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Out of Blink CORS
-const base::Feature kOutOfBlinkCors{"OutOfBlinkCORS",
+const base::Feature kOutOfBlinkCors{"OutOfBlinkCors",
                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kReporting{"Reporting", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 585209b8..e359937 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -5277,3 +5277,7 @@
 crbug.com/905694 [ Linux ] virtual/threaded/fast/scroll-behavior/smooth-scroll/scroll-during-selection.html [ Failure Pass ]
 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 ]
+
+#Sheriff 2018-11-19
+crbug.com/906591 [ Win10 ] printing/single-line-must-not-be-split-into-two-pages.html [ Failure ]
+crbug.com/906591 [ Win10 ] virtual/threaded/printing/single-line-must-not-be-split-into-two-pages.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index 65eefcb..d8194cf 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -474,92 +474,92 @@
   {
     "prefix": "outofblink-cors",
     "base": "external/wpt/fetch",
-    "args": ["--enable-features=OutOfBlinkCORS,ServiceWorkerServicification"]
+    "args": ["--enable-features=OutOfBlinkCors,ServiceWorkerServicification"]
   },
   {
     "prefix": "outofblink-cors",
     "base": "external/wpt/http",
-    "args": ["--enable-features=OutOfBlinkCORS,ServiceWorkerServicification"]
+    "args": ["--enable-features=OutOfBlinkCors,ServiceWorkerServicification"]
   },
   {
     "prefix": "outofblink-cors",
     "base": "external/wpt/referrer-policy",
-    "args": ["--enable-features=OutOfBlinkCORS,ServiceWorkerServicification"]
+    "args": ["--enable-features=OutOfBlinkCors,ServiceWorkerServicification"]
   },
   {
     "prefix": "outofblink-cors",
     "base": "external/wpt/service-workers",
-    "args": ["--enable-features=OutOfBlinkCORS,ServiceWorkerServicification"]
+    "args": ["--enable-features=OutOfBlinkCors,ServiceWorkerServicification"]
   },
   {
     "prefix": "outofblink-cors",
     "base": "external/wpt/xhr",
-    "args": ["--enable-features=OutOfBlinkCORS,ServiceWorkerServicification"]
+    "args": ["--enable-features=OutOfBlinkCors,ServiceWorkerServicification"]
   },
   {
     "prefix": "outofblink-cors",
     "base": "http/tests/fetch",
-    "args": ["--enable-features=OutOfBlinkCORS,ServiceWorkerServicification"]
+    "args": ["--enable-features=OutOfBlinkCors,ServiceWorkerServicification"]
   },
   {
     "prefix": "outofblink-cors",
     "base": "http/tests/navigation",
-    "args": ["--enable-features=OutOfBlinkCORS,ServiceWorkerServicification"]
+    "args": ["--enable-features=OutOfBlinkCors,ServiceWorkerServicification"]
   },
   {
     "prefix": "outofblink-cors",
     "base": "http/tests/security",
-    "args": ["--enable-features=OutOfBlinkCORS,ServiceWorkerServicification"]
+    "args": ["--enable-features=OutOfBlinkCors,ServiceWorkerServicification"]
   },
   {
     "prefix": "outofblink-cors",
     "base": "http/tests/xmlhttprequest",
-    "args": ["--enable-features=OutOfBlinkCORS,ServiceWorkerServicification"]
+    "args": ["--enable-features=OutOfBlinkCors,ServiceWorkerServicification"]
   },
   {
     "prefix": "outofblink-cors-ns",
     "base": "external/wpt/fetch",
-    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+    "args": ["--enable-features=OutOfBlinkCors,NetworkService"]
   },
   {
     "prefix": "outofblink-cors-ns",
     "base": "external/wpt/http",
-    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+    "args": ["--enable-features=OutOfBlinkCors,NetworkService"]
   },
   {
     "prefix": "outofblink-cors-ns",
     "base": "external/wpt/referrer-policy",
-    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+    "args": ["--enable-features=OutOfBlinkCors,NetworkService"]
   },
   {
     "prefix": "outofblink-cors-ns",
     "base": "external/wpt/service-workers",
-    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+    "args": ["--enable-features=OutOfBlinkCors,NetworkService"]
   },
   {
     "prefix": "outofblink-cors-ns",
     "base": "external/wpt/xhr",
-    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+    "args": ["--enable-features=OutOfBlinkCors,NetworkService"]
   },
   {
     "prefix": "outofblink-cors-ns",
     "base": "http/tests/fetch",
-    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+    "args": ["--enable-features=OutOfBlinkCors,NetworkService"]
   },
   {
     "prefix": "outofblink-cors-ns",
     "base": "http/tests/navigation",
-    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+    "args": ["--enable-features=OutOfBlinkCors,NetworkService"]
   },
   {
     "prefix": "outofblink-cors-ns",
     "base": "http/tests/security",
-    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+    "args": ["--enable-features=OutOfBlinkCors,NetworkService"]
   },
   {
     "prefix": "outofblink-cors-ns",
     "base": "http/tests/xmlhttprequest",
-    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+    "args": ["--enable-features=OutOfBlinkCors,NetworkService"]
   },
   {
     "prefix": "presentation",
diff --git a/third_party/WebKit/LayoutTests/animations/custom-properties/custom-length-percentage-list-type-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/custom-properties/custom-length-percentage-list-type-interpolation-expected.txt
index bb01e7f..5fe355b5 100644
--- a/third_party/WebKit/LayoutTests/animations/custom-properties/custom-length-percentage-list-type-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/animations/custom-properties/custom-length-percentage-list-type-interpolation-expected.txt
@@ -1,119 +1,119 @@
 This is a testharness.js-based test.
 PASS This test uses interpolation-test.js.
-PASS CSS Transitions: property <--length-percentage-list> from [initial] to [20% 200%] at (-0.3) is [46% calc(520px + -60%)]
+PASS CSS Transitions: property <--length-percentage-list> from [initial] to [20% 200%] at (-0.3) is [46% calc(-60% + 520px)]
 PASS CSS Transitions: property <--length-percentage-list> from [initial] to [20% 200%] at (0) is [40% 400px]
-PASS CSS Transitions: property <--length-percentage-list> from [initial] to [20% 200%] at (0.5) is [30% calc(200px + 100%)]
+PASS CSS Transitions: property <--length-percentage-list> from [initial] to [20% 200%] at (0.5) is [30% calc(100% + 200px)]
 PASS CSS Transitions: property <--length-percentage-list> from [initial] to [20% 200%] at (1) is [20% 200%]
-PASS CSS Transitions: property <--length-percentage-list> from [initial] to [20% 200%] at (1.5) is [10% calc(-200px + 300%)]
-PASS CSS Transitions: property <--length-percentage-list> from [inherit] to [20px 200%] at (-0.3) is [calc(-6px + 39%) calc(390px + -60%)]
+PASS CSS Transitions: property <--length-percentage-list> from [initial] to [20% 200%] at (1.5) is [10% calc(300% + -200px)]
+PASS CSS Transitions: property <--length-percentage-list> from [inherit] to [20px 200%] at (-0.3) is [calc(39% + -6px) calc(-60% + 390px)]
 PASS CSS Transitions: property <--length-percentage-list> from [inherit] to [20px 200%] at (0) is [30% 300px]
-PASS CSS Transitions: property <--length-percentage-list> from [inherit] to [20px 200%] at (0.5) is [calc(10px + 15%) calc(150px + 100%)]
+PASS CSS Transitions: property <--length-percentage-list> from [inherit] to [20px 200%] at (0.5) is [calc(15% + 10px) calc(100% + 150px)]
 PASS CSS Transitions: property <--length-percentage-list> from [inherit] to [20px 200%] at (1) is [20px 200%]
-PASS CSS Transitions: property <--length-percentage-list> from [inherit] to [20px 200%] at (1.5) is [calc(30px + -15%) calc(-150px + 300%)]
-PASS CSS Transitions: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (-0.3) is [calc(-30px + 16%) calc(490px + -36%)]
+PASS CSS Transitions: property <--length-percentage-list> from [inherit] to [20px 200%] at (1.5) is [calc(-15% + 30px) calc(300% + -150px)]
+PASS CSS Transitions: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (-0.3) is [calc(16% + -30px) calc(-36% + 490px)]
 PASS CSS Transitions: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (0) is [40% 400px]
-PASS CSS Transitions: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (0.5) is [calc(50px + 80%) calc(250px + 60%)]
-PASS CSS Transitions: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (1) is [calc(100px + 120%) calc(100px + 120%)]
-PASS CSS Transitions: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (1.5) is [calc(150px + 160%) calc(-50px + 180%)]
-PASS CSS Transitions: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (-0.3) is [calc(-16px + -16%) -160px]
-PASS CSS Transitions: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (0) is [calc(-10px + -10%) -100px]
+PASS CSS Transitions: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (0.5) is [calc(80% + 50px) calc(60% + 250px)]
+PASS CSS Transitions: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (1) is [calc(120% + 100px) calc(120% + 100px)]
+PASS CSS Transitions: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (1.5) is [calc(160% + 150px) calc(180% + -50px)]
+PASS CSS Transitions: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (-0.3) is [calc(-16% + -16px) -160px]
+PASS CSS Transitions: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (0) is [calc(-10% + -10px) -100px]
 PASS CSS Transitions: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (0.5) is [0% 0px]
-PASS CSS Transitions: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (1) is [calc(10px + 10%) 100px]
-PASS CSS Transitions: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (1.5) is [calc(20px + 20%) 200px]
-PASS CSS Transitions: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (-0.3) is [calc(140px + 13%) calc(1400px + -60%)]
-PASS CSS Transitions: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (0) is [calc(200px + 10%) 2000px]
-PASS CSS Transitions: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (0.5) is [calc(300px + 5%) calc(3000px + 100%)]
-PASS CSS Transitions: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (1) is [400px calc(4000px + 200%)]
-PASS CSS Transitions: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (1.5) is [calc(500px + -5%) calc(5000px + 300%)]
-PASS CSS Transitions: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (-0.3) is [calc(-30px + -30%)]
+PASS CSS Transitions: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (1) is [calc(10% + 10px) 100px]
+PASS CSS Transitions: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (1.5) is [calc(20% + 20px) 200px]
+PASS CSS Transitions: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (-0.3) is [calc(13% + 140px) calc(-60% + 1400px)]
+PASS CSS Transitions: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (0) is [calc(10% + 200px) 2000px]
+PASS CSS Transitions: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (0.5) is [calc(5% + 300px) calc(100% + 3000px)]
+PASS CSS Transitions: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (1) is [400px calc(200% + 4000px)]
+PASS CSS Transitions: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (1.5) is [calc(-5% + 500px) calc(300% + 5000px)]
+PASS CSS Transitions: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (-0.3) is [calc(-30% + -30px)]
 PASS CSS Transitions: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (0) is [0px]
-PASS CSS Transitions: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (0.5) is [calc(50px + 50%)]
-PASS CSS Transitions: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (1) is [calc(100px + 100%)]
-PASS CSS Transitions: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (1.5) is [calc(150px + 150%)]
+PASS CSS Transitions: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (0.5) is [calc(50% + 50px)]
+PASS CSS Transitions: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (1) is [calc(100% + 100px)]
+PASS CSS Transitions: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (1.5) is [calc(150% + 150px)]
 PASS CSS Transitions: property <--length-percentage-list> from neutral to [20% 200px] at (-0.3) is [7% 70px]
 PASS CSS Transitions: property <--length-percentage-list> from neutral to [20% 200px] at (0) is [10% 100px]
 PASS CSS Transitions: property <--length-percentage-list> from neutral to [20% 200px] at (0.5) is [15% 150px]
 PASS CSS Transitions: property <--length-percentage-list> from neutral to [20% 200px] at (1) is [20% 200px]
 PASS CSS Transitions: property <--length-percentage-list> from neutral to [20% 200px] at (1.5) is [25% 250px]
-PASS CSS Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (-0.3) is [46% calc(520px + -60%)]
+PASS CSS Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (-0.3) is [46% calc(-60% + 520px)]
 PASS CSS Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (0) is [40% 400px]
-PASS CSS Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (0.5) is [30% calc(200px + 100%)]
+PASS CSS Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (0.5) is [30% calc(100% + 200px)]
 PASS CSS Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (1) is [20% 200%]
-PASS CSS Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (1.5) is [10% calc(-200px + 300%)]
-PASS CSS Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (-0.3) is [calc(-6px + 39%) calc(390px + -60%)]
+PASS CSS Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (1.5) is [10% calc(300% + -200px)]
+PASS CSS Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (-0.3) is [calc(39% + -6px) calc(-60% + 390px)]
 PASS CSS Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (0) is [30% 300px]
-PASS CSS Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (0.5) is [calc(10px + 15%) calc(150px + 100%)]
+PASS CSS Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (0.5) is [calc(15% + 10px) calc(100% + 150px)]
 PASS CSS Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (1) is [20px 200%]
-PASS CSS Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (1.5) is [calc(30px + -15%) calc(-150px + 300%)]
-PASS CSS Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (-0.3) is [calc(-30px + 16%) calc(490px + -36%)]
+PASS CSS Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (1.5) is [calc(-15% + 30px) calc(300% + -150px)]
+PASS CSS Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (-0.3) is [calc(16% + -30px) calc(-36% + 490px)]
 PASS CSS Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (0) is [40% 400px]
-PASS CSS Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (0.5) is [calc(50px + 80%) calc(250px + 60%)]
-PASS CSS Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (1) is [calc(100px + 120%) calc(100px + 120%)]
-PASS CSS Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (1.5) is [calc(150px + 160%) calc(-50px + 180%)]
-PASS CSS Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (-0.3) is [calc(-16px + -16%) -160px]
-PASS CSS Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (0) is [calc(-10px + -10%) -100px]
+PASS CSS Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (0.5) is [calc(80% + 50px) calc(60% + 250px)]
+PASS CSS Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (1) is [calc(120% + 100px) calc(120% + 100px)]
+PASS CSS Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (1.5) is [calc(160% + 150px) calc(180% + -50px)]
+PASS CSS Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (-0.3) is [calc(-16% + -16px) -160px]
+PASS CSS Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (0) is [calc(-10% + -10px) -100px]
 PASS CSS Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (0.5) is [0% 0px]
-PASS CSS Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (1) is [calc(10px + 10%) 100px]
-PASS CSS Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (1.5) is [calc(20px + 20%) 200px]
-PASS CSS Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (-0.3) is [calc(140px + 13%) calc(1400px + -60%)]
-PASS CSS Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (0) is [calc(200px + 10%) 2000px]
-PASS CSS Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (0.5) is [calc(300px + 5%) calc(3000px + 100%)]
-PASS CSS Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (1) is [400px calc(4000px + 200%)]
-PASS CSS Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (1.5) is [calc(500px + -5%) calc(5000px + 300%)]
-PASS CSS Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (-0.3) is [calc(-30px + -30%)]
+PASS CSS Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (1) is [calc(10% + 10px) 100px]
+PASS CSS Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (1.5) is [calc(20% + 20px) 200px]
+PASS CSS Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (-0.3) is [calc(13% + 140px) calc(-60% + 1400px)]
+PASS CSS Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (0) is [calc(10% + 200px) 2000px]
+PASS CSS Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (0.5) is [calc(5% + 300px) calc(100% + 3000px)]
+PASS CSS Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (1) is [400px calc(200% + 4000px)]
+PASS CSS Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (1.5) is [calc(-5% + 500px) calc(300% + 5000px)]
+PASS CSS Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (-0.3) is [calc(-30% + -30px)]
 PASS CSS Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (0) is [0px]
-PASS CSS Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (0.5) is [calc(50px + 50%)]
-PASS CSS Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (1) is [calc(100px + 100%)]
-PASS CSS Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (1.5) is [calc(150px + 150%)]
+PASS CSS Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (0.5) is [calc(50% + 50px)]
+PASS CSS Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (1) is [calc(100% + 100px)]
+PASS CSS Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (1.5) is [calc(150% + 150px)]
 FAIL CSS Animations: property <--length-percentage-list> from neutral to [20% 200px] at (-0.3) is [-6% -60px] assert_equals: expected "7 % 70px " but got "- 6 % - 60px "
 FAIL CSS Animations: property <--length-percentage-list> from neutral to [20% 200px] at (0) is [0px 0px] assert_equals: expected "10 % 100px " but got "0px 0px "
 FAIL CSS Animations: property <--length-percentage-list> from neutral to [20% 200px] at (0.5) is [10% 100px] assert_equals: expected "15 % 150px " but got "10 % 100px "
 PASS CSS Animations: property <--length-percentage-list> from neutral to [20% 200px] at (1) is [20% 200px]
 FAIL CSS Animations: property <--length-percentage-list> from neutral to [20% 200px] at (1.5) is [30% 300px] assert_equals: expected "25 % 250px " but got "30 % 300px "
-PASS Web Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (-0.3) is [46% calc(520px + -60%)]
+PASS Web Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (-0.3) is [46% calc(-60% + 520px)]
 PASS Web Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (0) is [40% 400px]
-PASS Web Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (0.5) is [30% calc(200px + 100%)]
+PASS Web Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (0.5) is [30% calc(100% + 200px)]
 PASS Web Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (1) is [20% 200%]
-PASS Web Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (1.5) is [10% calc(-200px + 300%)]
-PASS Web Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (-0.3) is [calc(-6px + 39%) calc(390px + -60%)]
+PASS Web Animations: property <--length-percentage-list> from [initial] to [20% 200%] at (1.5) is [10% calc(300% + -200px)]
+PASS Web Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (-0.3) is [calc(39% + -6px) calc(-60% + 390px)]
 PASS Web Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (0) is [30% 300px]
-PASS Web Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (0.5) is [calc(10px + 15%) calc(150px + 100%)]
+PASS Web Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (0.5) is [calc(15% + 10px) calc(100% + 150px)]
 PASS Web Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (1) is [20px 200%]
-PASS Web Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (1.5) is [calc(30px + -15%) calc(-150px + 300%)]
-PASS Web Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (-0.3) is [calc(-30px + 16%) calc(490px + -36%)]
+PASS Web Animations: property <--length-percentage-list> from [inherit] to [20px 200%] at (1.5) is [calc(-15% + 30px) calc(300% + -150px)]
+PASS Web Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (-0.3) is [calc(16% + -30px) calc(-36% + 490px)]
 PASS Web Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (0) is [40% 400px]
-PASS Web Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (0.5) is [calc(50px + 80%) calc(250px + 60%)]
-PASS Web Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (1) is [calc(100px + 120%) calc(100px + 120%)]
-PASS Web Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (1.5) is [calc(150px + 160%) calc(-50px + 180%)]
-PASS Web Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (-0.3) is [calc(-16px + -16%) -160px]
-PASS Web Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (0) is [calc(-10px + -10%) -100px]
+PASS Web Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (0.5) is [calc(80% + 50px) calc(60% + 250px)]
+PASS Web Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (1) is [calc(120% + 100px) calc(120% + 100px)]
+PASS Web Animations: property <--length-percentage-list> from [unset] to [calc(100px + 120%) calc(100px + 120%)] at (1.5) is [calc(160% + 150px) calc(180% + -50px)]
+PASS Web Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (-0.3) is [calc(-16% + -16px) -160px]
+PASS Web Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (0) is [calc(-10% + -10px) -100px]
 PASS Web Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (0.5) is [0% 0px]
-PASS Web Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (1) is [calc(10px + 10%) 100px]
-PASS Web Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (1.5) is [calc(20px + 20%) 200px]
-PASS Web Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (-0.3) is [calc(140px + 13%) calc(1400px + -60%)]
-PASS Web Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (0) is [calc(200px + 10%) 2000px]
-PASS Web Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (0.5) is [calc(300px + 5%) calc(3000px + 100%)]
-PASS Web Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (1) is [400px calc(4000px + 200%)]
-PASS Web Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (1.5) is [calc(500px + -5%) calc(5000px + 300%)]
-PASS Web Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (-0.3) is [calc(-30px + -30%)]
+PASS Web Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (1) is [calc(10% + 10px) 100px]
+PASS Web Animations: property <--length-percentage-list> from [calc(-10px - 10%) -100px] to [calc(10px + 10%) 100px] at (1.5) is [calc(20% + 20px) 200px]
+PASS Web Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (-0.3) is [calc(13% + 140px) calc(-60% + 1400px)]
+PASS Web Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (0) is [calc(10% + 200px) 2000px]
+PASS Web Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (0.5) is [calc(5% + 300px) calc(100% + 3000px)]
+PASS Web Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (1) is [400px calc(200% + 4000px)]
+PASS Web Animations: property <--length-percentage-list> from [calc(10em + 10%) 100em] to [20em calc(200em + 200%)] at (1.5) is [calc(-5% + 500px) calc(300% + 5000px)]
+PASS Web Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (-0.3) is [calc(-30% + -30px)]
 PASS Web Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (0) is [0px]
-PASS Web Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (0.5) is [calc(50px + 50%)]
-PASS Web Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (1) is [calc(100px + 100%)]
-PASS Web Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (1.5) is [calc(150px + 150%)]
+PASS Web Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (0.5) is [calc(50% + 50px)]
+PASS Web Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (1) is [calc(100% + 100px)]
+PASS Web Animations: property <--length-percentage-list> from [0px] to [calc(100px + 100%)] at (1.5) is [calc(150% + 150px)]
 FAIL Web Animations: property <--length-percentage-list> from neutral to [20% 200px] at (-0.3) is [-6% -60px] assert_equals: expected "7 % 70px " but got "- 6 % - 60px "
 FAIL Web Animations: property <--length-percentage-list> from neutral to [20% 200px] at (0) is [0px 0px] assert_equals: expected "10 % 100px " but got "0px 0px "
 FAIL Web Animations: property <--length-percentage-list> from neutral to [20% 200px] at (0.5) is [10% 100px] assert_equals: expected "15 % 150px " but got "10 % 100px "
 PASS Web Animations: property <--length-percentage-list> from neutral to [20% 200px] at (1) is [20% 200px]
 FAIL Web Animations: property <--length-percentage-list> from neutral to [20% 200px] at (1.5) is [30% 300px] assert_equals: expected "25 % 250px " but got "30 % 300px "
-FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to add [110% 40px] at (-0.3) is [-20% 170px] assert_equals: expected "calc ( 50px + - 20 % ) calc ( 170px + 60 % ) " but got "- 20 % 170px "
-FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to add [110% 40px] at (0) is [10% 140px] assert_equals: expected "calc ( 50px + 10 % ) calc ( 140px + 60 % ) " but got "10 % 140px "
-FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to add [110% 40px] at (0.5) is [60% 90px] assert_equals: expected "calc ( 50px + 60 % ) calc ( 90px + 60 % ) " but got "60 % 90px "
-FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to add [110% 40px] at (1) is [110% 40px] assert_equals: expected "calc ( 50px + 110 % ) calc ( 40px + 60 % ) " but got "110 % 40px "
-FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to add [110% 40px] at (1.5) is [160% -10px] assert_equals: expected "calc ( 50px + 160 % ) calc ( - 10px + 60 % ) " but got "160 % - 10px "
-FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to replace [110% 40px] at (-0.3) is [-20% 170px] assert_equals: expected "calc ( 65px + - 20 % ) calc ( 170px + 78 % ) " but got "- 20 % 170px "
-FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to replace [110% 40px] at (0) is [10% 140px] assert_equals: expected "calc ( 50px + 10 % ) calc ( 140px + 60 % ) " but got "10 % 140px "
-FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to replace [110% 40px] at (0.5) is [60% 90px] assert_equals: expected "calc ( 25px + 60 % ) calc ( 90px + 30 % ) " but got "60 % 90px "
+FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to add [110% 40px] at (-0.3) is [-20% 170px] assert_equals: expected "calc ( - 20 % + 50px ) calc ( 60 % + 170px ) " but got "- 20 % 170px "
+FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to add [110% 40px] at (0) is [10% 140px] assert_equals: expected "calc ( 10 % + 50px ) calc ( 60 % + 140px ) " but got "10 % 140px "
+FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to add [110% 40px] at (0.5) is [60% 90px] assert_equals: expected "calc ( 60 % + 50px ) calc ( 60 % + 90px ) " but got "60 % 90px "
+FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to add [110% 40px] at (1) is [110% 40px] assert_equals: expected "calc ( 110 % + 50px ) calc ( 60 % + 40px ) " but got "110 % 40px "
+FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to add [110% 40px] at (1.5) is [160% -10px] assert_equals: expected "calc ( 160 % + 50px ) calc ( 60 % + - 10px ) " but got "160 % - 10px "
+FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to replace [110% 40px] at (-0.3) is [-20% 170px] assert_equals: expected "calc ( - 20 % + 65px ) calc ( 78 % + 170px ) " but got "- 20 % 170px "
+FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to replace [110% 40px] at (0) is [10% 140px] assert_equals: expected "calc ( 10 % + 50px ) calc ( 60 % + 140px ) " but got "10 % 140px "
+FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to replace [110% 40px] at (0.5) is [60% 90px] assert_equals: expected "calc ( 60 % + 25px ) calc ( 30 % + 90px ) " but got "60 % 90px "
 PASS Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to replace [110% 40px] at (1) is [110% 40px]
-FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to replace [110% 40px] at (1.5) is [160% -10px] assert_equals: expected "calc ( - 25px + 160 % ) calc ( - 10px + - 30 % ) " but got "160 % - 10px "
+FAIL Compositing: property <--length-percentage-list> underlying [50px 60%] from add [10% 140px] to replace [110% 40px] at (1.5) is [160% -10px] assert_equals: expected "calc ( 160 % + - 25px ) calc ( - 30 % + - 10px ) " but got "160 % - 10px "
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/animations/custom-properties/custom-length-percentage-list-type-interpolation.html b/third_party/WebKit/LayoutTests/animations/custom-properties/custom-length-percentage-list-type-interpolation.html
index cc0332d..4b7808e 100644
--- a/third_party/WebKit/LayoutTests/animations/custom-properties/custom-length-percentage-list-type-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/custom-properties/custom-length-percentage-list-type-interpolation.html
@@ -24,11 +24,11 @@
   from: 'initial',
   to: '20% 200%',
 }, [
-  {at: -0.3, is: '46% calc(520px - 60%)'},
+  {at: -0.3, is: '46% calc(-60% + 520px)'},
   {at: 0, is: '40% 400px'},
-  {at: 0.5, is: '30% calc(200px + 100%)'},
+  {at: 0.5, is: '30% calc(100% + 200px)'},
   {at: 1, is: '20% 200%'},
-  {at: 1.5, is: '10% calc(-200px + 300%)'},
+  {at: 1.5, is: '10% calc(300% + -200px)'},
 ]);
 
 assertInterpolation({
@@ -36,11 +36,11 @@
   from: 'inherit',
   to: '20px 200%',
 }, [
-  {at: -0.3, is: 'calc(-6px + 39%) calc(390px - 60%)'},
+  {at: -0.3, is: 'calc(39% + -6px) calc(-60% + 390px)'},
   {at: 0, is: '30% 300px'},
-  {at: 0.5, is: 'calc(10px + 15%) calc(150px + 100%)'},
+  {at: 0.5, is: 'calc(15% + 10px) calc(100% + 150px)'},
   {at: 1, is: '20px 200%'},
-  {at: 1.5, is: 'calc(30px - 15%) calc(-150px + 300%)'},
+  {at: 1.5, is: 'calc(-15% + 30px) calc(300% + -150px)'},
 ]);
 
 assertInterpolation({
@@ -48,11 +48,11 @@
   from: 'unset',
   to: 'calc(100px + 120%) calc(100px + 120%)',
 }, [
-  {at: -0.3, is: 'calc(-30px + 16%) calc(490px - 36%)'},
+  {at: -0.3, is: 'calc(16% + -30px) calc(-36% + 490px)'},
   {at: 0, is: '40% 400px'},
-  {at: 0.5, is: 'calc(50px + 80%) calc(250px + 60%)'},
-  {at: 1, is: 'calc(100px + 120%) calc(100px + 120%)'},
-  {at: 1.5, is: 'calc(150px + 160%) calc(-50px + 180%)'},
+  {at: 0.5, is: 'calc(80% + 50px) calc(60% + 250px)'},
+  {at: 1, is: 'calc(120% + 100px) calc(120% + 100px)'},
+  {at: 1.5, is: 'calc(160% + 150px) calc(180% + -50px)'},
 ]);
 
 assertInterpolation({
@@ -60,11 +60,11 @@
   from: 'calc(-10px - 10%) -100px',
   to: 'calc(10px + 10%) 100px',
 }, [
-  {at: -0.3, is: 'calc(-16px - 16%) -160px'},
-  {at: 0, is: 'calc(-10px - 10%) -100px'},
+  {at: -0.3, is: 'calc(-16% + -16px) -160px'},
+  {at: 0, is: 'calc(-10% + -10px) -100px'},
   {at: 0.5, is: '0% 0px'},
-  {at: 1, is: 'calc(10px + 10%) 100px'},
-  {at: 1.5, is: 'calc(20px + 20%) 200px'}
+  {at: 1, is: 'calc(10% + 10px) 100px'},
+  {at: 1.5, is: 'calc(20% + 20px) 200px'}
 ]);
 
 assertInterpolation({
@@ -72,11 +72,11 @@
   from: 'calc(10em + 10%) 100em',
   to: '20em calc(200em + 200%)',
 }, [
-  {at: -0.3, is: 'calc(140px + 13%) calc(1400px - 60%)'},
-  {at: 0, is: 'calc(200px + 10%) 2000px'},
-  {at: 0.5, is: 'calc(300px + 5%) calc(3000px + 100%)'},
-  {at: 1, is: '400px calc(4000px + 200%)'},
-  {at: 1.5, is: 'calc(500px - 5%) calc(5000px + 300%)'}
+  {at: -0.3, is: 'calc(13% + 140px) calc(-60% + 1400px)'},
+  {at: 0, is: 'calc(10% + 200px) 2000px'},
+  {at: 0.5, is: 'calc(5% + 300px) calc(100% + 3000px)'},
+  {at: 1, is: '400px calc(200% + 4000px)'},
+  {at: 1.5, is: 'calc(-5% + 500px) calc(300% + 5000px)'}
 ]);
 
 assertInterpolation({
@@ -84,11 +84,11 @@
   from: '0px',
   to: 'calc(100px + 100%)',
 }, [
-  {at: -0.3, is: 'calc(-30px - 30%)'},
+  {at: -0.3, is: 'calc(-30% + -30px)'},
   {at: 0, is: '0px'},
-  {at: 0.5, is: 'calc(50px + 50%)'},
-  {at: 1, is: 'calc(100px + 100%)'},
-  {at: 1.5, is: 'calc(150px + 150%)'}
+  {at: 0.5, is: 'calc(50% + 50px)'},
+  {at: 1, is: 'calc(100% + 100px)'},
+  {at: 1.5, is: 'calc(150% + 150px)'}
 ]);
 
 // Composition and neutralKeyframe tests assume that composite:add means
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/border-image-width-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/border-image-width-interpolation-expected.txt
index bedd234..28c4a0b7 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/border-image-width-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/border-image-width-interpolation-expected.txt
@@ -62,18 +62,18 @@
 PASS CSS Transitions: property <border-image-width> from [10px 20% 30 40px] to [80px 70% 60 50px] at (1.5) is [115px 95% 75 55px]
 PASS CSS Transitions: property <border-image-width> from [10px 20% 30 40px] to [80px 70% 60 50px] at (5) is [360px 270% 180 90px]
 PASS CSS Transitions: property <border-image-width> from [10px 20% 30 40px] to [80px 70% 60 50px] at (10) is [710px 520% 330 140px]
-FAIL CSS Transitions: property <border-image-width> from [10%] to [20px] at (-0.3) is [calc(-6px + 13%)] assert_equals: expected "7px " but got "calc ( - 6px + 13 % ) "
+FAIL CSS Transitions: property <border-image-width> from [10%] to [20px] at (-0.3) is [calc(13% + -6px)] assert_equals: expected "7px " but got "calc ( 13 % + - 6px ) "
 PASS CSS Transitions: property <border-image-width> from [10%] to [20px] at (0) is [10%]
-FAIL CSS Transitions: property <border-image-width> from [10%] to [20px] at (0.3) is [calc(6px + 7%)] assert_equals: expected "13px " but got "calc ( 6px + 7 % ) "
-FAIL CSS Transitions: property <border-image-width> from [10%] to [20px] at (0.6) is [calc(12px + 4%)] assert_equals: expected "16px " but got "calc ( 12px + 4 % ) "
+FAIL CSS Transitions: property <border-image-width> from [10%] to [20px] at (0.3) is [calc(7% + 6px)] assert_equals: expected "13px " but got "calc ( 7 % + 6px ) "
+FAIL CSS Transitions: property <border-image-width> from [10%] to [20px] at (0.6) is [calc(4% + 12px)] assert_equals: expected "16px " but got "calc ( 4 % + 12px ) "
 PASS CSS Transitions: property <border-image-width> from [10%] to [20px] at (1) is [20px]
-FAIL CSS Transitions: property <border-image-width> from [10%] to [20px] at (1.5) is [calc(30px + -5%)] assert_equals: expected "25px " but got "calc ( 30px + - 5 % ) "
-FAIL CSS Transitions: property <border-image-width> from [10px] to [20%] at (-0.3) is [calc(13px + -6%)] assert_equals: expected "7px " but got "calc ( 13px + - 6 % ) "
+FAIL CSS Transitions: property <border-image-width> from [10%] to [20px] at (1.5) is [calc(-5% + 30px)] assert_equals: expected "25px " but got "calc ( - 5 % + 30px ) "
+FAIL CSS Transitions: property <border-image-width> from [10px] to [20%] at (-0.3) is [calc(-6% + 13px)] assert_equals: expected "7px " but got "calc ( - 6 % + 13px ) "
 PASS CSS Transitions: property <border-image-width> from [10px] to [20%] at (0) is [10px]
-FAIL CSS Transitions: property <border-image-width> from [10px] to [20%] at (0.3) is [calc(7px + 6%)] assert_equals: expected "13px " but got "calc ( 7px + 6 % ) "
-FAIL CSS Transitions: property <border-image-width> from [10px] to [20%] at (0.6) is [calc(4px + 12%)] assert_equals: expected "16px " but got "calc ( 4px + 12 % ) "
+FAIL CSS Transitions: property <border-image-width> from [10px] to [20%] at (0.3) is [calc(6% + 7px)] assert_equals: expected "13px " but got "calc ( 6 % + 7px ) "
+FAIL CSS Transitions: property <border-image-width> from [10px] to [20%] at (0.6) is [calc(12% + 4px)] assert_equals: expected "16px " but got "calc ( 12 % + 4px ) "
 PASS CSS Transitions: property <border-image-width> from [10px] to [20%] at (1) is [20%]
-FAIL CSS Transitions: property <border-image-width> from [10px] to [20%] at (1.5) is [calc(-5px + 30%)] assert_equals: expected "25px " but got "calc ( - 5px + 30 % ) "
+FAIL CSS Transitions: property <border-image-width> from [10px] to [20%] at (1.5) is [calc(30% + -5px)] assert_equals: expected "25px " but got "calc ( 30 % + - 5px ) "
 PASS CSS Transitions: property <border-image-width> from [10px auto auto 20] to [110px auto auto 120] at (-0.3) is [0px auto auto 0]
 PASS CSS Transitions: property <border-image-width> from [10px auto auto 20] to [110px auto auto 120] at (0) is [10px auto auto 20]
 PASS CSS Transitions: property <border-image-width> from [10px auto auto 20] to [110px auto auto 120] at (0.3) is [40px auto auto 50]
@@ -177,18 +177,18 @@
 PASS CSS Transitions with transition: all: property <border-image-width> from [10px 20% 30 40px] to [80px 70% 60 50px] at (1.5) is [115px 95% 75 55px]
 PASS CSS Transitions with transition: all: property <border-image-width> from [10px 20% 30 40px] to [80px 70% 60 50px] at (5) is [360px 270% 180 90px]
 PASS CSS Transitions with transition: all: property <border-image-width> from [10px 20% 30 40px] to [80px 70% 60 50px] at (10) is [710px 520% 330 140px]
-FAIL CSS Transitions with transition: all: property <border-image-width> from [10%] to [20px] at (-0.3) is [calc(-6px + 13%)] assert_equals: expected "7px " but got "calc ( - 6px + 13 % ) "
+FAIL CSS Transitions with transition: all: property <border-image-width> from [10%] to [20px] at (-0.3) is [calc(13% + -6px)] assert_equals: expected "7px " but got "calc ( 13 % + - 6px ) "
 PASS CSS Transitions with transition: all: property <border-image-width> from [10%] to [20px] at (0) is [10%]
-FAIL CSS Transitions with transition: all: property <border-image-width> from [10%] to [20px] at (0.3) is [calc(6px + 7%)] assert_equals: expected "13px " but got "calc ( 6px + 7 % ) "
-FAIL CSS Transitions with transition: all: property <border-image-width> from [10%] to [20px] at (0.6) is [calc(12px + 4%)] assert_equals: expected "16px " but got "calc ( 12px + 4 % ) "
+FAIL CSS Transitions with transition: all: property <border-image-width> from [10%] to [20px] at (0.3) is [calc(7% + 6px)] assert_equals: expected "13px " but got "calc ( 7 % + 6px ) "
+FAIL CSS Transitions with transition: all: property <border-image-width> from [10%] to [20px] at (0.6) is [calc(4% + 12px)] assert_equals: expected "16px " but got "calc ( 4 % + 12px ) "
 PASS CSS Transitions with transition: all: property <border-image-width> from [10%] to [20px] at (1) is [20px]
-FAIL CSS Transitions with transition: all: property <border-image-width> from [10%] to [20px] at (1.5) is [calc(30px + -5%)] assert_equals: expected "25px " but got "calc ( 30px + - 5 % ) "
-FAIL CSS Transitions with transition: all: property <border-image-width> from [10px] to [20%] at (-0.3) is [calc(13px + -6%)] assert_equals: expected "7px " but got "calc ( 13px + - 6 % ) "
+FAIL CSS Transitions with transition: all: property <border-image-width> from [10%] to [20px] at (1.5) is [calc(-5% + 30px)] assert_equals: expected "25px " but got "calc ( - 5 % + 30px ) "
+FAIL CSS Transitions with transition: all: property <border-image-width> from [10px] to [20%] at (-0.3) is [calc(-6% + 13px)] assert_equals: expected "7px " but got "calc ( - 6 % + 13px ) "
 PASS CSS Transitions with transition: all: property <border-image-width> from [10px] to [20%] at (0) is [10px]
-FAIL CSS Transitions with transition: all: property <border-image-width> from [10px] to [20%] at (0.3) is [calc(7px + 6%)] assert_equals: expected "13px " but got "calc ( 7px + 6 % ) "
-FAIL CSS Transitions with transition: all: property <border-image-width> from [10px] to [20%] at (0.6) is [calc(4px + 12%)] assert_equals: expected "16px " but got "calc ( 4px + 12 % ) "
+FAIL CSS Transitions with transition: all: property <border-image-width> from [10px] to [20%] at (0.3) is [calc(6% + 7px)] assert_equals: expected "13px " but got "calc ( 6 % + 7px ) "
+FAIL CSS Transitions with transition: all: property <border-image-width> from [10px] to [20%] at (0.6) is [calc(12% + 4px)] assert_equals: expected "16px " but got "calc ( 12 % + 4px ) "
 PASS CSS Transitions with transition: all: property <border-image-width> from [10px] to [20%] at (1) is [20%]
-FAIL CSS Transitions with transition: all: property <border-image-width> from [10px] to [20%] at (1.5) is [calc(-5px + 30%)] assert_equals: expected "25px " but got "calc ( - 5px + 30 % ) "
+FAIL CSS Transitions with transition: all: property <border-image-width> from [10px] to [20%] at (1.5) is [calc(30% + -5px)] assert_equals: expected "25px " but got "calc ( 30 % + - 5px ) "
 PASS CSS Transitions with transition: all: property <border-image-width> from [10px auto auto 20] to [110px auto auto 120] at (-0.3) is [0px auto auto 0]
 PASS CSS Transitions with transition: all: property <border-image-width> from [10px auto auto 20] to [110px auto auto 120] at (0) is [10px auto auto 20]
 PASS CSS Transitions with transition: all: property <border-image-width> from [10px auto auto 20] to [110px auto auto 120] at (0.3) is [40px auto auto 50]
@@ -292,18 +292,18 @@
 PASS CSS Animations: property <border-image-width> from [10px 20% 30 40px] to [80px 70% 60 50px] at (1.5) is [115px 95% 75 55px]
 PASS CSS Animations: property <border-image-width> from [10px 20% 30 40px] to [80px 70% 60 50px] at (5) is [360px 270% 180 90px]
 PASS CSS Animations: property <border-image-width> from [10px 20% 30 40px] to [80px 70% 60 50px] at (10) is [710px 520% 330 140px]
-FAIL CSS Animations: property <border-image-width> from [10%] to [20px] at (-0.3) is [calc(-6px + 13%)] assert_equals: expected "7px " but got "calc ( - 6px + 13 % ) "
+FAIL CSS Animations: property <border-image-width> from [10%] to [20px] at (-0.3) is [calc(13% + -6px)] assert_equals: expected "7px " but got "calc ( 13 % + - 6px ) "
 PASS CSS Animations: property <border-image-width> from [10%] to [20px] at (0) is [10%]
-FAIL CSS Animations: property <border-image-width> from [10%] to [20px] at (0.3) is [calc(6px + 7%)] assert_equals: expected "13px " but got "calc ( 6px + 7 % ) "
-FAIL CSS Animations: property <border-image-width> from [10%] to [20px] at (0.6) is [calc(12px + 4%)] assert_equals: expected "16px " but got "calc ( 12px + 4 % ) "
+FAIL CSS Animations: property <border-image-width> from [10%] to [20px] at (0.3) is [calc(7% + 6px)] assert_equals: expected "13px " but got "calc ( 7 % + 6px ) "
+FAIL CSS Animations: property <border-image-width> from [10%] to [20px] at (0.6) is [calc(4% + 12px)] assert_equals: expected "16px " but got "calc ( 4 % + 12px ) "
 PASS CSS Animations: property <border-image-width> from [10%] to [20px] at (1) is [20px]
-FAIL CSS Animations: property <border-image-width> from [10%] to [20px] at (1.5) is [calc(30px + -5%)] assert_equals: expected "25px " but got "calc ( 30px + - 5 % ) "
-FAIL CSS Animations: property <border-image-width> from [10px] to [20%] at (-0.3) is [calc(13px + -6%)] assert_equals: expected "7px " but got "calc ( 13px + - 6 % ) "
+FAIL CSS Animations: property <border-image-width> from [10%] to [20px] at (1.5) is [calc(-5% + 30px)] assert_equals: expected "25px " but got "calc ( - 5 % + 30px ) "
+FAIL CSS Animations: property <border-image-width> from [10px] to [20%] at (-0.3) is [calc(-6% + 13px)] assert_equals: expected "7px " but got "calc ( - 6 % + 13px ) "
 PASS CSS Animations: property <border-image-width> from [10px] to [20%] at (0) is [10px]
-FAIL CSS Animations: property <border-image-width> from [10px] to [20%] at (0.3) is [calc(7px + 6%)] assert_equals: expected "13px " but got "calc ( 7px + 6 % ) "
-FAIL CSS Animations: property <border-image-width> from [10px] to [20%] at (0.6) is [calc(4px + 12%)] assert_equals: expected "16px " but got "calc ( 4px + 12 % ) "
+FAIL CSS Animations: property <border-image-width> from [10px] to [20%] at (0.3) is [calc(6% + 7px)] assert_equals: expected "13px " but got "calc ( 6 % + 7px ) "
+FAIL CSS Animations: property <border-image-width> from [10px] to [20%] at (0.6) is [calc(12% + 4px)] assert_equals: expected "16px " but got "calc ( 12 % + 4px ) "
 PASS CSS Animations: property <border-image-width> from [10px] to [20%] at (1) is [20%]
-FAIL CSS Animations: property <border-image-width> from [10px] to [20%] at (1.5) is [calc(-5px + 30%)] assert_equals: expected "25px " but got "calc ( - 5px + 30 % ) "
+FAIL CSS Animations: property <border-image-width> from [10px] to [20%] at (1.5) is [calc(30% + -5px)] assert_equals: expected "25px " but got "calc ( 30 % + - 5px ) "
 PASS CSS Animations: property <border-image-width> from [10px auto auto 20] to [110px auto auto 120] at (-0.3) is [0px auto auto 0]
 PASS CSS Animations: property <border-image-width> from [10px auto auto 20] to [110px auto auto 120] at (0) is [10px auto auto 20]
 PASS CSS Animations: property <border-image-width> from [10px auto auto 20] to [110px auto auto 120] at (0.3) is [40px auto auto 50]
@@ -407,18 +407,18 @@
 PASS Web Animations: property <border-image-width> from [10px 20% 30 40px] to [80px 70% 60 50px] at (1.5) is [115px 95% 75 55px]
 PASS Web Animations: property <border-image-width> from [10px 20% 30 40px] to [80px 70% 60 50px] at (5) is [360px 270% 180 90px]
 PASS Web Animations: property <border-image-width> from [10px 20% 30 40px] to [80px 70% 60 50px] at (10) is [710px 520% 330 140px]
-FAIL Web Animations: property <border-image-width> from [10%] to [20px] at (-0.3) is [calc(-6px + 13%)] assert_equals: expected "7px " but got "calc ( - 6px + 13 % ) "
+FAIL Web Animations: property <border-image-width> from [10%] to [20px] at (-0.3) is [calc(13% + -6px)] assert_equals: expected "7px " but got "calc ( 13 % + - 6px ) "
 PASS Web Animations: property <border-image-width> from [10%] to [20px] at (0) is [10%]
-FAIL Web Animations: property <border-image-width> from [10%] to [20px] at (0.3) is [calc(6px + 7%)] assert_equals: expected "13px " but got "calc ( 6px + 7 % ) "
-FAIL Web Animations: property <border-image-width> from [10%] to [20px] at (0.6) is [calc(12px + 4%)] assert_equals: expected "16px " but got "calc ( 12px + 4 % ) "
+FAIL Web Animations: property <border-image-width> from [10%] to [20px] at (0.3) is [calc(7% + 6px)] assert_equals: expected "13px " but got "calc ( 7 % + 6px ) "
+FAIL Web Animations: property <border-image-width> from [10%] to [20px] at (0.6) is [calc(4% + 12px)] assert_equals: expected "16px " but got "calc ( 4 % + 12px ) "
 PASS Web Animations: property <border-image-width> from [10%] to [20px] at (1) is [20px]
-FAIL Web Animations: property <border-image-width> from [10%] to [20px] at (1.5) is [calc(30px + -5%)] assert_equals: expected "25px " but got "calc ( 30px + - 5 % ) "
-FAIL Web Animations: property <border-image-width> from [10px] to [20%] at (-0.3) is [calc(13px + -6%)] assert_equals: expected "7px " but got "calc ( 13px + - 6 % ) "
+FAIL Web Animations: property <border-image-width> from [10%] to [20px] at (1.5) is [calc(-5% + 30px)] assert_equals: expected "25px " but got "calc ( - 5 % + 30px ) "
+FAIL Web Animations: property <border-image-width> from [10px] to [20%] at (-0.3) is [calc(-6% + 13px)] assert_equals: expected "7px " but got "calc ( - 6 % + 13px ) "
 PASS Web Animations: property <border-image-width> from [10px] to [20%] at (0) is [10px]
-FAIL Web Animations: property <border-image-width> from [10px] to [20%] at (0.3) is [calc(7px + 6%)] assert_equals: expected "13px " but got "calc ( 7px + 6 % ) "
-FAIL Web Animations: property <border-image-width> from [10px] to [20%] at (0.6) is [calc(4px + 12%)] assert_equals: expected "16px " but got "calc ( 4px + 12 % ) "
+FAIL Web Animations: property <border-image-width> from [10px] to [20%] at (0.3) is [calc(6% + 7px)] assert_equals: expected "13px " but got "calc ( 6 % + 7px ) "
+FAIL Web Animations: property <border-image-width> from [10px] to [20%] at (0.6) is [calc(12% + 4px)] assert_equals: expected "16px " but got "calc ( 12 % + 4px ) "
 PASS Web Animations: property <border-image-width> from [10px] to [20%] at (1) is [20%]
-FAIL Web Animations: property <border-image-width> from [10px] to [20%] at (1.5) is [calc(-5px + 30%)] assert_equals: expected "25px " but got "calc ( - 5px + 30 % ) "
+FAIL Web Animations: property <border-image-width> from [10px] to [20%] at (1.5) is [calc(30% + -5px)] assert_equals: expected "25px " but got "calc ( 30 % + - 5px ) "
 PASS Web Animations: property <border-image-width> from [10px auto auto 20] to [110px auto auto 120] at (-0.3) is [0px auto auto 0]
 PASS Web Animations: property <border-image-width> from [10px auto auto 20] to [110px auto auto 120] at (0) is [10px auto auto 20]
 PASS Web Animations: property <border-image-width> from [10px auto auto 20] to [110px auto auto 120] at (0.3) is [40px auto auto 50]
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/transform-interpolation-005.html b/third_party/WebKit/LayoutTests/animations/interpolation/transform-interpolation-005.html
index 728e6c72..0697cb35 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/transform-interpolation-005.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/transform-interpolation-005.html
@@ -30,31 +30,92 @@
 <script src="resources/interpolation-test.js"></script>
 <script>
 
-// Matrix
+// Matrix transforms:
+
+// 2D matrix transforms:
+//
+// [m11 m21 0 m41]   [1 0 0 Tx] [cos(R) -sin(R) 0 0] [1 K 0 0] [Sx 0  0 0]
+// [m12 m22 0 m42] = [0 1 0 Ty] [sin(R)  cos(R) 0 0] [0 1 0 0] [0  Sy 0 0]
+// [ 0   0  1  0 ]   [0 0 1 0 ] [  0       0    1 0] [0 0 1 0] [0  0  1 0]
+// [ 0   0  0  1 ]   [0 0 0 1 ] [  0       0    0 1] [0 0 0 1] [0  0  0 1]
+//
+// M = translate * rotate * skew * scale
+// See also webkit-transform-interpolation-005.html
+//
+
+const cos30 = Math.cos(Math.PI / 6);
+const sin30 = Math.sin(Math.PI / 6);
+const cos45 = Math.cos(Math.PI / 4);
+const sin45 = Math.sin(Math.PI / 4);
+const cos60 = Math.cos(Math.PI / 3);
+const sin60 = Math.sin(Math.PI / 3);
+
+// translateY(-6px) -> translateX(6px) rotate(90deg) scaleX(7)
 assertInterpolation({
   property: 'transform',
-  from: 'matrix(5, 6, 10, 7, 21, 23)',
-  to: 'matrix(8, 4, 9, 11, 24, 22)'
+  from: 'matrix(1, 0, 0, 1, 0, -6)',
+  to: 'matrix(0, 7, -1, 0, 6, 0)'
 }, [
-  {at: -1, is: 'matrix(-21.971399357258385, -10.985699678629187, -50.57889827616046, -38.946928317003575, 18, 24)'},
-  {at: 0, is: 'matrix(5, 6, 10, 7, 21, 23)'},
-  {at: 0.25, is: 'matrix(1.5045862850823934, 2.1375701058706307, 1.9887759643453702, 1.2132035030840276, 21.75, 22.75)'},
-  {at: 0.75, is: 'matrix(3.1847985591364396, 1.2803008685850275, 4.4228208119507615, 5.537010031441669, 23.25, 22.25)'},
-  {at: 1, is: 'matrix(8, 4, 9, 11, 24, 22)'},
-  {at: 2, is: 'matrix(-16.45196668627737, -19.74236002353284, -18.81066272622538, 0.5900238929654478, 27, 21)'},
+  {at: -1, is: 'matrix(0, 5, 1, 0, -6, -12)'},
+  {at: 0, is: 'matrix(1, 0, 0, 1, 0, -6)'},
+  {
+    at: 1/3,
+    is: `matrix(${3 * cos30}, ${3 * sin30}, -${sin30}, ${cos30}, 2, -4)`
+  },
+  {
+    at: 0.5,
+    is: `matrix(${4 * cos45}, ${4 * sin45}, -${sin45}, ${cos45}, 3, -3)`
+  },
+  {
+    at: 2/3,
+    is: `matrix(${5 * cos60}, ${5 * sin60}, -${sin60}, ${cos60}, 4, -2)`
+  },
+  {at: 1, is: 'matrix(0, 7, -1, 0, 6, 0)'},
+  {at: 2, is: 'matrix(-13, 0, 0, -1, 12, 6)'}
 ]);
+
+// translateX(6px) rotate(90deg) scaleX(7) -> translateY(-6px)
 assertInterpolation({
   property: 'transform',
-  from: 'matrix(43.30127018922194, 30, -17.5, 36.373066958946424, 31, 33)',
-  to: 'matrix(36, 31.17691453623979, -76.2102355330306, 22, 34, 32)'
+  from: 'matrix(0, 7, -1, 0, 6, 0)',
+  to: 'matrix(1, 0, 0, 1, 0, -6)',
 }, [
-  {at: -1, is: 'matrix(50.7191465922708, 27.5802296277601, 4.91128504689649, 17.7046464595868, 28, 34)'},
-  {at: 0, is: 'matrix(43.30127018922194, 30, -17.5, 36.373066958946424, 31, 33)'},
-  {at: 0.25, is: 'matrix(41.4579172764046, 30.4088866283282, -29.1438768223581, 36.3267603016693, 31.75, 32.75)'},
-  {at: 0.75, is: 'matrix(37.8045038027911, 30.9964317800692, -58.6633288853787, 29.3063176731403, 33.25, 32.25)'},
-  {at: 1, is: 'matrix(36, 31.17691453623979, -76.2102355330306, 22, 34, 32)'},
-  {at: 2, is: 'matrix(28.9928082708843, 31.1691829526532, -160.742351276266, -35.9984985114527, 37, 31)'},
+  {at: -1, is: 'matrix(-13, 0, 0, -1, 12, 6)'},
+  {at: 0, is: 'matrix(0, 7, -1, 0, 6, 0)'},
+   {
+    at: 1/3,
+    is: `matrix(${5 * cos60}, ${5 * sin60}, -${sin60}, ${cos60}, 4, -2)`
+  },
+  {
+    at: 0.5,
+    is: `matrix(${4 * cos45}, ${4 * sin45}, -${sin45}, ${cos45}, 3, -3)`
+  },
+  {
+    at: 2/3,
+    is: `matrix(${3 * cos30}, ${3 * sin30}, -${sin30}, ${cos30}, 2, -4)`
+  },
+  {at: 1, is: 'matrix(1, 0, 0, 1, 0, -6)'},
+  {at: 2, is: 'matrix(0, 5, 1, 0, -6, -12)'}
 ]);
+
+// scaleY(7) -> skewX(45deg) scaleX(7)
+assertInterpolation({
+  property: 'transform',
+  from: 'matrix(1, 0, 0, 7, 0, 0)',
+  to: 'matrix(7, 0, 1, 1, 0, 0)'
+}, [
+  {at: -1, is: 'matrix(-5, 0, -13, 13, 0, 0)'},
+  {at: 0, is: 'matrix(1, 0, 0, 7, 0, 0)'},
+  {at: 1/3, is: 'matrix(3, 0, 1.6667, 5, 0, 0)'},
+  {at: 0.5, is: 'matrix(4, 0, 2, 4, 0, 0)'},
+  {at: 2/3, is: 'matrix(5, 0, 2, 3, 0, 0)'},
+  {at: 1, is: `matrix(7, 0, 1, 1, 0, 0)`},
+  {at: 2, is: `matrix(13, 0, -10, -5, 0, 0)`}
+]);
+
+// 3-D matrix transforms.
+// TODO(kevers): Revisit 3D transform examples. It is difficult to infer
+// the quality of the matrix decompositions from the expected output.
 assertInterpolation({
   property: 'transform',
   from: 'none',
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-transform-interpolation-005.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-transform-interpolation-005.html
index 2e19b3d..74315a2 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-transform-interpolation-005.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-transform-interpolation-005.html
@@ -30,31 +30,59 @@
 <script src="resources/interpolation-test.js"></script>
 <script>
 
-// Matrix
+// Matrix transforms:
+
+// 2-D Matrix transforms:
+// See also transform-interpolation-005.html
+
+// none -> translateX(6px) skewX(45deg) scaleX(7) scaleY(2)
 assertInterpolation({
   property: '-webkit-transform',
-  from: 'matrix(5, 6, 10, 7, 21, 23)',
-  to: 'matrix(8, 4, 9, 11, 24, 22)'
+  from: 'none',
+  to: 'matrix(7, 0, 2, 2, 6, 0)'
 }, [
-  {at: -1, is: 'matrix(-21.971399357258385, -10.985699678629187, -50.57889827616046, -38.946928317003575, 18, 24)'},
-  {at: 0, is: 'matrix(5, 6, 10, 7, 21, 23)'},
-  {at: 0.25, is: 'matrix(1.5045862850823934, 2.1375701058706307, 1.9887759643453702, 1.2132035030840276, 21.75, 22.75)'},
-  {at: 0.75, is: 'matrix(3.1847985591364396, 1.2803008685850275, 4.4228208119507615, 5.537010031441669, 23.25, 22.25)'},
-  {at: 1, is: 'matrix(8, 4, 9, 11, 24, 22)'},
-  {at: 2, is: 'matrix(-16.45196668627737, -19.74236002353284, -18.81066272622538, 0.5900238929654478, 27, 21)'},
+  {at: -1, is: 'matrix(-5, 0, 0, 0, -6, 0)'},
+  {at: 0, is: 'matrix(1, 0, 0, 1, 0, 0)'},
+  {at: 0.25, is: 'matrix(2.5, 0, 0.31, 1.25, 1.5, 0)'},
+  {at: 0.5, is: 'matrix(4, 0, 0.75, 1.5, 3, 0)'},
+  {at: 0.75, is: 'matrix(5.5, 0, 1.31, 1.75, 4.5, 0)'},
+  {at: 1, is: 'matrix(7, 0, 2, 2, 6, 0)'},
+  {at: 2, is: 'matrix(13, 0, 6, 3, 12, 0)'}
 ]);
+
+// translateY(-6px) scale(3, 5) -> none
 assertInterpolation({
   property: '-webkit-transform',
-  from: 'matrix(43.30127018922194, 30, -17.5, 36.373066958946424, 31, 33)',
-  to: 'matrix(36, 31.17691453623979, -76.2102355330306, 22, 34, 32)'
+  from: 'matrix(3, 0, 0, 5, 0, -6)',
+  to: 'none'
 }, [
-  {at: -1, is: 'matrix(50.7191465922708, 27.5802296277601, 4.91128504689649, 17.7046464595868, 28, 34)'},
-  {at: 0, is: 'matrix(43.30127018922194, 30, -17.5, 36.373066958946424, 31, 33)'},
-  {at: 0.25, is: 'matrix(41.4579172764046, 30.4088866283282, -29.1438768223581, 36.3267603016693, 31.75, 32.75)'},
-  {at: 0.75, is: 'matrix(37.8045038027911, 30.9964317800692, -58.6633288853787, 29.3063176731403, 33.25, 32.25)'},
-  {at: 1, is: 'matrix(36, 31.17691453623979, -76.2102355330306, 22, 34, 32)'},
-  {at: 2, is: 'matrix(28.9928082708843, 31.1691829526532, -160.742351276266, -35.9984985114527, 37, 31)'},
+  {at: -1, is: 'matrix(5, 0, 0, 9, 0, -12)'},
+  {at: 0, is: 'matrix(3, 0, 0, 5, 0, -6)'},
+  {at: 0.25, is: 'matrix(2.5, 0, 0, 4, 0, -4.5)'},
+  {at: 0.5, is: 'matrix(2, 0, 0, 3, 0, -3)'},
+  {at: 0.75, is: 'matrix(1.5, 0, 0, 2, 0, -1.5)'},
+  {at: 1, is: 'matrix(1, 0, 0, 1, 0, 0)'},
+  {at: 2, is: 'matrix(-1, 0, 0, -3, 0, 6)'}
 ]);
+
+// translateY(-6px) scale(3, 5) -> translateX(6px) skewX(1) scale(7, 2)
+assertInterpolation({
+  property: '-webkit-transform',
+  from: 'matrix(3, 0, 0, 5, 0, -6)',
+  to: 'matrix(7, 0, 2, 2, 6, 0)'
+}, [
+  {at: -1, is: 'matrix(-1, 0, -8, 8, -6, -12)'},
+  {at: 0, is: 'matrix(3, 0, 0, 5, 0, -6)'},
+  {at: 0.25, is: 'matrix(4, 0, 1.06, 4.25, 1.5, -4.5)'},
+  {at: 0.5, is: 'matrix(5, 0, 1.75, 3.5, 3, -3)'},
+  {at: 0.75, is: 'matrix(6, 0, 2.06, 2.75, 4.5, -1.5)'},
+  {at: 1, is: 'matrix(7, 0, 2, 2, 6, 0)'},
+  {at: 2, is: 'matrix(11, 0, -2, -1, 12, 6)'}
+]);
+
+// 3-D matrix transforms.
+// TODO(kevers): Revisit 3D transform examples. Verbatim copies of transforms
+// in transform-interpolation-005.html.
 assertInterpolation({
   property: '-webkit-transform',
   from: 'none',
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-shapeMargin.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-shapeMargin.html
index 1b160b26..f3bc8b9 100644
--- a/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-shapeMargin.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-shapeMargin.html
@@ -18,7 +18,7 @@
     player.currentTime = 5;
     element.style.fontSize = '20px';
     element.style.width = '100px';
-    assert_equals(getComputedStyle(element).shapeMargin, 'calc(30px + 40%)');
+    assert_equals(getComputedStyle(element).shapeMargin, 'calc(40% + 30px)');
 }, 'shapeMargin responsive to style changes');
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-to-style-change.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-to-style-change.html
index 825cf642..0cb99bc 100644
--- a/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-to-style-change.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-to-style-change.html
@@ -16,11 +16,11 @@
     var player = element.animate([{left: 'calc(100px + 80%)'}, {left: '10em'}], 10);
     player.pause();
     player.currentTime = 5;
-    assert_equals(getComputedStyle(element).left, 'calc(100px + 40%)');
+    assert_equals(getComputedStyle(element).left, 'calc(40% + 100px)');
     element.style.fontSize = '20px';
-    assert_equals(getComputedStyle(element).left, 'calc(150px + 40%)');
+    assert_equals(getComputedStyle(element).left, 'calc(40% + 150px)');
     container.style.width = '500px';
-    assert_equals(getComputedStyle(element).left, 'calc(150px + 40%)');
+    assert_equals(getComputedStyle(element).left, 'calc(40% + 150px)');
 }, 'Lengths responsive to style changes');
 
 test(function() {
diff --git a/third_party/WebKit/LayoutTests/css3/calc/getComputedStyle-border-radius-expected.txt b/third_party/WebKit/LayoutTests/css3/calc/getComputedStyle-border-radius-expected.txt
index 1201506..67f3098 100644
--- a/third_party/WebKit/LayoutTests/css3/calc/getComputedStyle-border-radius-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/calc/getComputedStyle-border-radius-expected.txt
@@ -2,11 +2,11 @@
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
-PASS getComputedStyle(document.getElementById('calc'), null).getPropertyValue('border-top-left-radius') is "calc(10px + 25%) calc(20px + 25%)"
-PASS getComputedStyle(document.getElementById('calc'), null).getPropertyValue('border-top-right-radius') is "calc(10px + 25%)"
+PASS getComputedStyle(document.getElementById('calc'), null).getPropertyValue('border-top-left-radius') is "calc(25% + 10px) calc(25% + 20px)"
+PASS getComputedStyle(document.getElementById('calc'), null).getPropertyValue('border-top-right-radius') is "calc(25% + 10px)"
 PASS getComputedStyle(document.getElementById('calc'), null).getPropertyValue('border-bottom-right-radius') is "25%"
 PASS getComputedStyle(document.getElementById('calc'), null).getPropertyValue('border-bottom-left-radius') is "25px"
-PASS getComputedStyle(document.getElementById('calc'), null).getPropertyValue('border-radius') is "calc(10px + 25%) calc(10px + 25%) 25% 25px / calc(20px + 25%) calc(10px + 25%) 25% 25px"
+PASS getComputedStyle(document.getElementById('calc'), null).getPropertyValue('border-radius') is "calc(25% + 10px) calc(25% + 10px) 25% 25px / calc(25% + 20px) calc(25% + 10px) 25% 25px"
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/css3/calc/getComputedStyle-border-radius.html b/third_party/WebKit/LayoutTests/css3/calc/getComputedStyle-border-radius.html
index 8e4197d..48c5ff0 100644
--- a/third_party/WebKit/LayoutTests/css3/calc/getComputedStyle-border-radius.html
+++ b/third_party/WebKit/LayoutTests/css3/calc/getComputedStyle-border-radius.html
@@ -20,9 +20,9 @@
 
 description("Tests calling getPropertyValue on computed border radii involving CSS calc");
 
-test('border-top-left-radius', 'calc(10px + 25%) calc(20px + 25%)');
-test('border-top-right-radius', 'calc(10px + 25%)');
+test('border-top-left-radius', 'calc(25% + 10px) calc(25% + 20px)');
+test('border-top-right-radius', 'calc(25% + 10px)');
 test('border-bottom-right-radius', '25%');
 test('border-bottom-left-radius', '25px');
-test('border-radius', 'calc(10px + 25%) calc(10px + 25%) 25% 25px / calc(20px + 25%) calc(10px + 25%) 25% 25px');
+test('border-radius', 'calc(25% + 10px) calc(25% + 10px) 25% 25px / calc(25% + 20px) calc(25% + 10px) 25% 25px');
 </script>
diff --git a/third_party/WebKit/LayoutTests/css3/calc/getComputedStyle-calc-assert.html b/third_party/WebKit/LayoutTests/css3/calc/getComputedStyle-calc-assert.html
index b59f5109..756a06dc 100644
--- a/third_party/WebKit/LayoutTests/css3/calc/getComputedStyle-calc-assert.html
+++ b/third_party/WebKit/LayoutTests/css3/calc/getComputedStyle-calc-assert.html
@@ -11,9 +11,9 @@
 <div id="calc"></div>
 <script>
 test(function() {
-    assert_equals(getComputedStyle(calc).backgroundPositionX, "calc(10px + 20%)", "background-position-x");
-    assert_equals(getComputedStyle(calc).backgroundPositionY, "calc(30px + 40%)", "background-position-y");
-    assert_equals(getComputedStyle(calc).verticalAlign, "calc(50px + 60%)", "vertical-align");
-    assert_equals(getComputedStyle(calc).flexBasis, "calc(70px + 80%)", "flex-basis");
+    assert_equals(getComputedStyle(calc).backgroundPositionX, "calc(20% + 10px)", "background-position-x");
+    assert_equals(getComputedStyle(calc).backgroundPositionY, "calc(40% + 30px)", "background-position-y");
+    assert_equals(getComputedStyle(calc).verticalAlign, "calc(60% + 50px)", "vertical-align");
+    assert_equals(getComputedStyle(calc).flexBasis, "calc(80% + 70px)", "flex-basis");
 }, "Tests getComputedStyle works with calc for various properties");
 </script>
diff --git a/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing-expected.txt b/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing-expected.txt
index 1e86258..4f2c2d0 100644
--- a/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing-expected.txt
@@ -69,9 +69,9 @@
 PASS flexitem.style.flex is "1 2 3px"
 PASS getComputedStyle(flexitem).flex is "1 2 3px"
 PASS flexitem.style.flex is "4 3 calc(20px + 40%)"
-PASS getComputedStyle(flexitem).flex is "4 3 calc(20px + 40%)"
+PASS getComputedStyle(flexitem).flex is "4 3 calc(40% + 20px)"
 PASS flexitem.style.flex is "1 2 calc(10px + 50%)"
-PASS getComputedStyle(flexitem).flex is "1 2 calc(10px + 50%)"
+PASS getComputedStyle(flexitem).flex is "1 2 calc(50% + 10px)"
 PASS flexitem.style.flex is "0 0 auto"
 PASS getComputedStyle(flexitem).flex is "0 0 auto"
 PASS flexitem.style.flex is "0 1 auto"
diff --git a/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing.html b/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing.html
index 3ddb4c78..0904fdb 100644
--- a/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing.html
+++ b/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing.html
@@ -151,11 +151,11 @@
 
 flexitem.style.flex = 'calc(20px + 40%) 4 3';
 shouldBeEqualToString('flexitem.style.flex', '4 3 calc(20px + 40%)');
-shouldBeEqualToString('getComputedStyle(flexitem).flex', '4 3 calc(20px + 40%)');
+shouldBeEqualToString('getComputedStyle(flexitem).flex', '4 3 calc(40% + 20px)');
 
 flexitem.style.flex = '1 2 calc(10px + 50%)';
 shouldBeEqualToString('flexitem.style.flex', '1 2 calc(10px + 50%)');
-shouldBeEqualToString('getComputedStyle(flexitem).flex', '1 2 calc(10px + 50%)');
+shouldBeEqualToString('getComputedStyle(flexitem).flex', '1 2 calc(50% + 10px)');
 
 flexitem.style.flex = 'auto 0 0';
 shouldBeEqualToString('flexitem.style.flex', '0 0 auto');
diff --git a/third_party/WebKit/LayoutTests/custom-elements/tentative/HTMLElement-attachInternals.html b/third_party/WebKit/LayoutTests/custom-elements/tentative/HTMLElement-attachInternals.html
new file mode 100644
index 0000000..3721dc9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/custom-elements/tentative/HTMLElement-attachInternals.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<body>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<div id="container"></div>
+<script>
+test(() => {
+  class MyElement1 extends HTMLElement {
+  }
+  customElements.define('my-element1', MyElement1);
+  const container = document.querySelector('#container');
+
+  let element = new MyElement1();
+  assert_true(element.attachInternals() instanceof ElementInternals,
+              'New - 1st call');
+  assert_throws('InvalidStateError', () => { element.attachInternals(); },
+                'New - 2nd call');
+
+  element = document.createElement('my-element1');
+  assert_true(element.attachInternals() instanceof ElementInternals,
+              'createElement - 1st call');
+  assert_throws('InvalidStateError', () => { element.attachInternals(); },
+                'createElement - 2nd call');
+
+  container.innerHTML = '<my-element1></my-element1>';
+  assert_true(container.firstChild.attachInternals() instanceof ElementInternals,
+              'Parser - 1st call');
+  assert_throws('InvalidStateError', () => {
+    container.firstChild.attachInternals();
+  }, 'Parser - 2nd call');
+}, 'Successful attachInternals() and the second call.');
+
+test(() => {
+  const builtin = document.createElement('div');
+  assert_throws('InvalidStateError', () => { builtin.attachInternals() });
+
+  const undefinedCustom = document.createElement('my-element');
+  assert_throws('InvalidStateError', () => { undefinedCustom.attachInternals() });
+}, 'If a custom element definition for the local name of the element doesn\'t' +
+     ' exist, throw an InvalidStateError');
+
+test(() => {
+  class MyElement2 extends HTMLElement {
+    static get disabledFeatures() { return ['internals']; }
+  }
+  customElements.define('my-element2', MyElement2);
+  const container = document.querySelector('#container');
+
+  assert_throws('InvalidStateError', () => {
+    (new MyElement2).attachInternals();
+  });
+  assert_throws('InvalidStateError', () => {
+    document.createElement('my-element2').attachInternals();
+  });
+  assert_throws('InvalidStateError', () => {
+    container.innerHTML = '<my-element2></my-element2>';
+    container.firstChild.attachInternals();
+  });
+}, 'If a custom element definition for the local name of the element has ' +
+     'disable internals flag, throw an InvalidStateError');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/editing/selection/select-out-of-floated-non-editable.html b/third_party/WebKit/LayoutTests/editing/selection/select-out-of-floated-non-editable.html
deleted file mode 100644
index 3daa646..0000000
--- a/third_party/WebKit/LayoutTests/editing/selection/select-out-of-floated-non-editable.html
+++ /dev/null
@@ -1,107 +0,0 @@
-<!doctype html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../assert_selection.js"></script>
-<script>
-const kFontSize = '10px';
-const kMouseStep = '5';
-function startDrag(x, y) {
-  assert_own_property(window, 'eventSender', 'This test requires window.eventSender');
-  eventSender.dragMode = false;
-
-  // Clear click count
-  eventSender.mouseMoveTo(0, 0);
-  eventSender.mouseDown();
-  eventSender.mouseUp();
-
-  eventSender.mouseMoveTo(x, y);
-  eventSender.mouseDown();
-}
-
-function endDrag() {
-  eventSender.mouseUp();
-}
-
-function testIt(sample, offset, expected, expectedText, description) {
-  test(() => assert_selection(
-    sample,
-    selection => {
-      selection.document.body.style.fontFamily = 'monospace';
-      selection.document.body.style.fontSize = kFontSize;
-      const target = selection.document.querySelector('.target');
-      const x = selection.computeLeft(target);
-      const right = x + target.offsetWidth + offset*kMouseStep;
-      const y = selection.computeTop(target);
-      startDrag(x, y);
-      eventSender.mouseMoveTo(right, y);
-      endDrag();
-      assert_equals(selection.toString(), expectedText);
-    },
-    expected),
-    description);
-}
-
-const kSample1 = '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">One float</div><div style="float: left">Another float</div>inline-level text after the floats';
-testIt(kSample1, 2,
-    '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div><div style="float: left">Another float</div>|inline-level text after the floats',
-    "One floatAnother float",
-    "Dragging 2 mouse-steps out of a float element with margin in a block-level with block level text before and another float and inline-level text after floats.");
-testIt(kSample1, 5,
-    '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div><div style="float: left">A|nother float</div>inline-level text after the floats',
-    "One floatA",
-    "Dragging 5 mouse-steps out of a float element with margin in a block-level with block level text before and another float and inline-level text after floats.");
-testIt(kSample1, 20,
-    '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div><div style="float: left">Another float</div>|inline-level text after the floats',
-    "One floatAnother float",
-    "Dragging 20 mouse-steps out of a float element with margin in a block-level with block level text before and another float and inline-level text after floats.");
-testIt(kSample1, 30,
-    '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div><div style="float: left">Another float</div>inline-le|vel text after the floats',
-    "One floatAnother floatinline-le",
-    "Dragging 30 mouse-steps out of a float element with margin in a block-level with block level text before and another float and inline-level text after floats.");
-
-const kSample2 = '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">One float</div>inline-level text after the floats';
-testIt(kSample2, 2,
-    '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div>|inline-level text after the floats',
-    "One float",
-    "Dragging 2 mouse-steps out of a float element with margin in a block-level with block level text before and inline-level text after floats.");
-testIt(kSample2, 5,
-    '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div>i|nline-level text after the floats',
-    "One floati",
-    "Dragging 5 mouse-steps out of a float element with margin in a block-level with block level text before and inline-level text after floats.");
-
-const kSample3 = '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">One float</div><div style="float: left">Another float</div>';
-testIt(kSample3, 2,
-    '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div><div style="float: left">|Another float</div>',
-    "One float",
-    "Dragging 2 mouse-steps out of a float element with margin in a block-level with block level text before and another float after.");
-testIt(kSample3, 5,
-    '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div><div style="float: left">A|nother float</div>',
-    "One floatA",
-    "Dragging 5 mouse-steps out of a float element with margin in a block-level with block level text before and another float after.");
-testIt(kSample3, 20,
-    '<div>block-level text before floats</div><div class="target" style="float: left; margin-right: 20px">^One float</div><div style="float: left">Another float|</div>',
-    "One floatAnother float",
-    "Dragging 20 mouse-steps out of a float element with margin in a block-level with block level text before and another float after.");
-
-const kSample4 = '<div>block-level text before floats</div><div class="target" style="float: left;">One float</div><div style="float: left">Another float</div>';
-testIt(kSample4, 0,
-    '<div>block-level text before floats</div><div class="target" style="float: left;">^One float</div><div style="float: left">|Another float</div>',
-    "One float",
-    "Dragging 0 mouse-steps out of a float element in a block-level with block level text before and another float after.");
-testIt(kSample4, 1,
-    '<div>block-level text before floats</div><div class="target" style="float: left;">^One float</div><div style="float: left">A|nother float</div>',
-    "One floatA",
-    "Dragging 2 mouse-steps out of a float element in a block-level with block level text before and another float after.");
-
-const kSample5 = '<div>block-level text before floats</div><div class="target" style="float: left;">One float</div>';
-testIt(kSample5, 2,
-    '<div>block-level text before floats</div><div class="target" style="float: left;">^One float|</div>',
-    "One float",
-    "Dragging 2 mouse-steps out of a float element in a block-level with block level text before .");
-
-const kSample6 = '<div><div>block-level text before floats</div><div class="target" style="float: left;">One float</div></div><p>Additional block-level sibling</p>';
-testIt(kSample6, 10,
-    '<div><div>block-level text before floats</div><div class="target" style="float: left;">^One float|</div></div><p>Additional block-level sibling</p>',
-    "One float",
-    "Dragging 2 mouse-steps out of a float element in a block-level with block level text before with an additional block-level sibling.");
-</script>
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
index e41c885..b85274cb 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
@@ -52987,6 +52987,18 @@
      {}
     ]
    ],
+   "css/css-multicol/multicol-span-all-dynamic-remove-007.html": [
+    [
+     "/css/css-multicol/multicol-span-all-dynamic-remove-007.html",
+     [
+      [
+       "/css/css-multicol/multicol-span-all-dynamic-remove-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-multicol/multicol-span-all-list-item-001.html": [
     [
      "/css/css-multicol/multicol-span-all-list-item-001.html",
@@ -151335,6 +151347,11 @@
      {}
     ]
    ],
+   "custom-elements/CustomElementRegistry-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "custom-elements/HTMLElement-constructor-expected.txt": [
     [
      {}
@@ -182655,6 +182672,21 @@
      {}
     ]
    ],
+   "webrtc-quic/META.yml": [
+    [
+     {}
+    ]
+   ],
+   "webrtc-quic/RTCQuicStream-helper.js": [
+    [
+     {}
+    ]
+   ],
+   "webrtc-quic/RTCQuicTransport-helper.js": [
+    [
+     {}
+    ]
+   ],
    "webrtc-stats/META.yml": [
     [
      {}
@@ -182930,16 +182962,6 @@
      {}
     ]
    ],
-   "webrtc/RTCQuicStream-helper.js": [
-    [
-     {}
-    ]
-   ],
-   "webrtc/RTCQuicTransport-helper.js": [
-    [
-     {}
-    ]
-   ],
    "webrtc/RTCRtpCapabilities-helper.js": [
     [
      {}
@@ -274407,6 +274429,18 @@
      {}
     ]
    ],
+   "webrtc-quic/RTCQuicStream.https.html": [
+    [
+     "/webrtc-quic/RTCQuicStream.https.html",
+     {}
+    ]
+   ],
+   "webrtc-quic/RTCQuicTransport.https.html": [
+    [
+     "/webrtc-quic/RTCQuicTransport.https.html",
+     {}
+    ]
+   ],
    "webrtc-stats/idlharness.window.js": [
     [
      "/webrtc-stats/idlharness.window.html",
@@ -274747,18 +274781,6 @@
      {}
     ]
    ],
-   "webrtc/RTCQuicStream.https.html": [
-    [
-     "/webrtc/RTCQuicStream.https.html",
-     {}
-    ]
-   ],
-   "webrtc/RTCQuicTransport.https.html": [
-    [
-     "/webrtc/RTCQuicTransport.https.html",
-     {}
-    ]
-   ],
    "webrtc/RTCRtpParameters-codecs.html": [
     [
      "/webrtc/RTCRtpParameters-codecs.html",
@@ -340408,6 +340430,10 @@
    "bbcce11c40fb0ef58b686cd4879103bcdfabc479",
    "reftest"
   ],
+  "css/css-multicol/multicol-span-all-dynamic-remove-007.html": [
+   "5b23814aed9cef84c83997198c80e169bc37c1d6",
+   "reftest"
+  ],
   "css/css-multicol/multicol-span-all-list-item-001-ref.html": [
    "4f3fe18a6d5804a4a7a6874fd46d5614c0a8dff2",
    "support"
@@ -376348,6 +376374,10 @@
    "695e489df3ceb99ec911c05e99f14e1c1b1fe8fb",
    "reftest"
   ],
+  "custom-elements/CustomElementRegistry-expected.txt": [
+   "daa93a401e4bc2ed4480a6b7e70f6ddccbc37bed",
+   "support"
+  ],
   "custom-elements/CustomElementRegistry.html": [
    "ecc7810e8df8acfb251cf93bd992a3e1266d51dd",
    "testharness"
@@ -439144,6 +439174,26 @@
    "90363662f742fbf1d31634030d2b470e08fe1421",
    "support"
   ],
+  "webrtc-quic/META.yml": [
+   "740c8d2fe84beafbcb7f98cef29aff2378721132",
+   "support"
+  ],
+  "webrtc-quic/RTCQuicStream-helper.js": [
+   "a87668f5a21eebd64f810029330989c5be10f037",
+   "support"
+  ],
+  "webrtc-quic/RTCQuicStream.https.html": [
+   "08c3a54a950830573761950b76bb420067de86b6",
+   "testharness"
+  ],
+  "webrtc-quic/RTCQuicTransport-helper.js": [
+   "7e28feae0937d4a28710be5f0e807c4af0f7c039",
+   "support"
+  ],
+  "webrtc-quic/RTCQuicTransport.https.html": [
+   "081f0b4d976e54301953621a9ef43d3f2c57aa8e",
+   "testharness"
+  ],
   "webrtc-stats/META.yml": [
    "10bcf856eb9258e0845f2fdcb6e08c43ebcdf78a",
    "support"
@@ -439588,22 +439638,6 @@
    "7de7fcaeb10ef209ece63ad346f668e1c634c4db",
    "testharness"
   ],
-  "webrtc/RTCQuicStream-helper.js": [
-   "a87668f5a21eebd64f810029330989c5be10f037",
-   "support"
-  ],
-  "webrtc/RTCQuicStream.https.html": [
-   "d7bed6da0144347b3f749173b427c0c4f88e05ba",
-   "testharness"
-  ],
-  "webrtc/RTCQuicTransport-helper.js": [
-   "7e28feae0937d4a28710be5f0e807c4af0f7c039",
-   "support"
-  ],
-  "webrtc/RTCQuicTransport.https.html": [
-   "3bcc93d95375ccf0bbaa8ba892606099ec8f0bf4",
-   "testharness"
-  ],
   "webrtc/RTCRtpCapabilities-helper.js": [
    "fb297c35fb1126e8985ff2f2a0dd1dd824ca5c1d",
    "support"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/column-gap-parsing-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/column-gap-parsing-001.html
index a0a92a9..7feeddf8 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/column-gap-parsing-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/column-gap-parsing-001.html
@@ -86,7 +86,7 @@
     test(
       function(){
         var target = document.getElementById("columnGapCalcFixedPercent");
-        assert_equals(getComputedStyle(target).columnGap, "calc(5px + 10%)");
+        assert_equals(getComputedStyle(target).columnGap, "calc(10% + 5px)");
       }, "column-gap accepts calc() mixing fixed and percentage values");
     test(
       function(){
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/gap-parsing-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/gap-parsing-001.html
index 0a2a9bda7..9ff3872 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/gap-parsing-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/gap-parsing-001.html
@@ -140,8 +140,8 @@
     test(
       function(){
         var target = document.getElementById("gapCalcFixedPercent");
-        assert_equals(getComputedStyle(target).rowGap, "calc(5px + 10%)");
-        assert_equals(getComputedStyle(target).columnGap, "calc(5px + 10%)");
+        assert_equals(getComputedStyle(target).rowGap, "calc(10% + 5px)");
+        assert_equals(getComputedStyle(target).columnGap, "calc(10% + 5px)");
       }, "gap accepts calc() mixing fixed and percentage values");
     test(
       function(){
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/grid-column-gap-parsing-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/grid-column-gap-parsing-001.html
index 66d8199..baec064 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/grid-column-gap-parsing-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/grid-column-gap-parsing-001.html
@@ -86,7 +86,7 @@
     test(
       function(){
         var target = document.getElementById("columnGapCalcFixedPercent");
-        assert_equals(getComputedStyle(target).columnGap, "calc(5px + 10%)");
+        assert_equals(getComputedStyle(target).columnGap, "calc(10% + 5px)");
       }, "grid-column-gap accepts calc() mixing fixed and percentage values");
     test(
       function(){
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/grid-gap-parsing-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/grid-gap-parsing-001.html
index aa43f772..fc10b62 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/grid-gap-parsing-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/grid-gap-parsing-001.html
@@ -140,8 +140,8 @@
     test(
       function(){
         var target = document.getElementById("gapCalcFixedPercent");
-        assert_equals(getComputedStyle(target).rowGap, "calc(5px + 10%)");
-        assert_equals(getComputedStyle(target).columnGap, "calc(5px + 10%)");
+        assert_equals(getComputedStyle(target).rowGap, "calc(10% + 5px)");
+        assert_equals(getComputedStyle(target).columnGap, "calc(10% + 5px)");
       }, "grid-gap accepts calc() mixing fixed and percentage values");
     test(
       function(){
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/grid-row-gap-parsing-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/grid-row-gap-parsing-001.html
index e394ea1..d3b44f4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/grid-row-gap-parsing-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/grid-row-gap-parsing-001.html
@@ -86,7 +86,7 @@
     test(
       function(){
         var target = document.getElementById("rowGapCalcFixedPercent");
-        assert_equals(getComputedStyle(target).rowGap, "calc(5px + 10%)");
+        assert_equals(getComputedStyle(target).rowGap, "calc(10% + 5px)");
       }, "grid-row-gap accepts calc() mixing fixed and percentage values");
     test(
       function(){
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/row-gap-parsing-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/row-gap-parsing-001.html
index 71b971d3..59be718 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/row-gap-parsing-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align/gaps/row-gap-parsing-001.html
@@ -86,7 +86,7 @@
     test(
       function(){
         var target = document.getElementById("rowGapCalcFixedPercent");
-        assert_equals(getComputedStyle(target).rowGap, "calc(5px + 10%)");
+        assert_equals(getComputedStyle(target).rowGap, "calc(10% + 5px)");
       }, "row-gap accepts calc() mixing fixed and percentage values");
     test(
       function(){
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-span-all-dynamic-remove-007.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-span-all-dynamic-remove-007.html
new file mode 100644
index 0000000..5b23814
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-span-all-dynamic-remove-007.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Remove the position:fixed spanner as the first child</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
+  <link rel="match" href="multicol-span-all-dynamic-remove-001-ref.html">
+  <meta name="assert" content="This test checks removing a position:fixed 'column-span:all' element (which doesn't actually span columns) should be rendered correctly.">
+
+  <script>
+  function runTest() {
+    document.body.offsetHeight;
+
+    document.getElementById("spanner").remove();
+
+    document.documentElement.removeAttribute("class");
+  }
+  </script>
+
+  <style>
+  #column {
+    column-count: 3;
+    column-rule: 6px solid;
+    width: 400px;
+    outline: 1px solid black;
+  }
+  h3 {
+    position: fixed;
+    column-span: all;
+    outline: 1px solid blue;
+  }
+  </style>
+
+  <body onload="runTest();">
+    <article id="column">
+      <h3 id="spanner">spanner</h3>
+      <div>block1</div>
+      <div>block2</div>
+    </article>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/registered-property-interpolation-004.https.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/registered-property-interpolation-004.https.html
index 1596a93..430326a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/registered-property-interpolation-004.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/registered-property-interpolation-004.https.html
@@ -15,7 +15,7 @@
         name: '--prop', syntax: '<length-percentage>'
       });
 
-      expectWorkletValue(target, '--prop', '[CSSMathSum calc(5px + 10%)]');
+      expectWorkletValue(target, '--prop', '[CSSMathSum calc(10% + 5px)]');
     } catch(e) {
       document.body.textContent = e;
       takeScreenshot();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/registered-property-value-009.https.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/registered-property-value-009.https.html
index 795770f..2ce2a0d5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/registered-property-value-009.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-paint-api/registered-property-value-009.https.html
@@ -33,12 +33,12 @@
 
       target.style.setProperty('--prop-1', '10%');
       target.style.setProperty('--prop-2', '10px');
-      target.style.setProperty('--prop-3', 'calc(10px + 10%)');
+      target.style.setProperty('--prop-3', 'calc(10% + 10px)');
 
       expectWorkletValues(target, {
         '--prop-1': ['[CSSUnitValue 10%]'],
         '--prop-2': ['[CSSUnitValue 10px]'],
-        '--prop-3': ['[CSSMathSum calc(10px + 10%)]'],
+        '--prop-3': ['[CSSMathSum calc(10% + 10px)]'],
       });
     } catch(e) {
       document.body.textContent = e;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-properties-values-api/registered-property-computation.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-properties-values-api/registered-property-computation.html
index 2525e43e..b1e5d237 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-properties-values-api/registered-property-computation.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-properties-values-api/registered-property-computation.html
@@ -103,25 +103,25 @@
 
 test_computed_value('<length-percentage>', '17em', '170px');
 test_computed_value('<length-percentage>', '18%', '18%');
-test_computed_value('<length-percentage>', 'calc(19em - 2%)', 'calc(190px + -2%)');
+test_computed_value('<length-percentage>', 'calc(19em - 2%)', 'calc(-2% + 190px)');
 
 test_computed_value('<length>#', '10px, 3em', '10px, 30px');
 test_computed_value('<length>#', '4em ,9px', '40px, 9px');
 test_computed_value('<length>#', '8em', '80px');
 
 test_computed_value('<length-percentage>#', '3% , 10vmax  , 22px', ['3%', length_ref('10vmax'), '22px'].join(', '));
-test_computed_value('<length-percentage>#', 'calc(50% + 1em), 4px', 'calc(10px + 50%), 4px');
-test_computed_value('<length-percentage>#', 'calc(13% + 37px)', 'calc(37px + 13%)');
+test_computed_value('<length-percentage>#', 'calc(50% + 1em), 4px', 'calc(50% + 10px), 4px');
+test_computed_value('<length-percentage>#', 'calc(13% + 37px)', 'calc(13% + 37px)');
 
 test_computed_value('<length>+', '10px 3em', '10px 30px');
 test_computed_value('<length>+', '4em 9px', '40px 9px');
 
 test_computed_value('<length-percentage>+', '3% 10vmax 22px', ['3%', length_ref('10vmax'), '22px'].join(' '));
-test_computed_value('<length-percentage>+', 'calc(50% + 1em) 4px', 'calc(10px + 50%) 4px');
+test_computed_value('<length-percentage>+', 'calc(50% + 1em) 4px', 'calc(50% + 10px) 4px');
 
 test_computed_value('<transform-function>', 'translateX(2px)', 'translateX(2px)');
 test_computed_value('<transform-function>', 'translateX(10em)', 'translateX(100px)');
-test_computed_value('<transform-function>', 'translateX(calc(11em + 10%))', 'translateX(calc(110px + 10%))');
+test_computed_value('<transform-function>', 'translateX(calc(11em + 10%))', 'translateX(calc(10% + 110px))');
 test_computed_value('<transform-function>+', 'translateX(10%) scale(2)', 'translateX(10%) scale(2)');
 
 test_computed_value('<integer>', '15', '15');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-properties-values-api/registered-property-initial.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-properties-values-api/registered-property-initial.html
index 77aa9cd1..82a012e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-properties-values-api/registered-property-initial.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-properties-values-api/registered-property-initial.html
@@ -17,7 +17,7 @@
 }
 
 test_initial_value({ syntax: '<length>', initialValue: 'calc(10px + 15px)' }, '25px');
-test_initial_value({ syntax: '<length-percentage>', initialValue: 'calc(1in + 10% + 4px)' }, 'calc(100px + 10%)');
+test_initial_value({ syntax: '<length-percentage>', initialValue: 'calc(1in + 10% + 4px)' }, 'calc(10% + 100px)');
 test_initial_value({ syntax: '<color>', initialValue: 'pink', inherits: true }, 'rgb(255, 192, 203)');
 test_initial_value({ syntax: '<color>', initialValue: 'purple' }, 'rgb(128, 0, 128)');
 test_initial_value({ syntax: '<transform-function>', initialValue: 'rotate(42deg)' }, 'rotate(42deg)');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-margin-003-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-margin-003-expected.txt
index 62062868..104e0bb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-margin-003-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-margin-003-expected.txt
@@ -11,7 +11,7 @@
 PASS calc(30%) - computed style
 PASS calc(100%/4) - computed style
 PASS calc(25%*3) - computed style
-PASS calc(25%*3 - 10in) - computed style
-FAIL calc((12.5%*6 + 10in) / 4) - computed style assert_in_array: value "calc(240px + 18.75%)" not in array ["calc((75% + 960px) / 4)", "calc(18.75% + 240px)"]
+FAIL calc(25%*3 - 10in) - computed style assert_in_array: value "calc(75% + -960px)" not in array ["calc(75% - 960px)", "calc(-960px + 75%)"]
+PASS calc((12.5%*6 + 10in) / 4) - computed style
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-010-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-010-expected.txt
index 3ce035e8..f6d4093 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-010-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-010-expected.txt
@@ -11,7 +11,7 @@
 PASS circle(calc(30%)) - computed style
 PASS circle(calc(100%/4)) - computed style
 PASS circle(calc(25%*3)) - computed style
-PASS circle(calc(25%*3 - 10in)) - computed style
-FAIL circle(calc((12.5%*6 + 10in) / 4)) - computed style assert_in_array: value "circle(calc(240px + 18.75%) at 50% 50%)" not in array ["circle(calc((75% + 960px) / 4) at 50% 50%)", "circle(calc(18.75% + 240px) at 50% 50%)"]
+FAIL circle(calc(25%*3 - 10in)) - computed style assert_in_array: value "circle(calc(75% + -960px) at 50% 50%)" not in array ["circle(calc(75% - 960px) at 50% 50%)", "circle(calc(-960px + 75%) at 50% 50%)"]
+PASS circle(calc((12.5%*6 + 10in) / 4)) - computed style
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-011-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-011-expected.txt
index fb6a89f..823faea1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-011-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-011-expected.txt
@@ -11,7 +11,7 @@
 PASS circle(at calc(30%)) - computed style
 PASS circle(at calc(100%/4)) - computed style
 PASS circle(at calc(25%*3)) - computed style
-PASS circle(at calc(25%*3 - 10in)) - computed style
-FAIL circle(at calc((12.5%*6 + 10in) / 4)) - computed style assert_in_array: value "circle(at calc(240px + 18.75%) 50%)" not in array ["circle(at calc((75% + 960px) / 4) 50%)", "circle(at calc(18.75% + 240px) 50%)"]
+FAIL circle(at calc(25%*3 - 10in)) - computed style assert_in_array: value "circle(at calc(75% + -960px) 50%)" not in array ["circle(at calc(75% - 960px) 50%)", "circle(at calc(-960px + 75%) 50%)"]
+PASS circle(at calc((12.5%*6 + 10in) / 4)) - computed style
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-010-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-010-expected.txt
index 7a8a207..d2bcdb9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-010-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-010-expected.txt
@@ -25,21 +25,21 @@
 PASS ellipse(calc(30%)) - computed style
 PASS ellipse(calc(100%/4)) - computed style
 PASS ellipse(calc(25%*3)) - computed style
-PASS ellipse(calc(25%*3 - 10in)) - computed style
-FAIL ellipse(calc((12.5%*6 + 10in) / 4)) - computed style assert_in_array: value "ellipse(calc(240px + 18.75%) at 50% 50%)" not in array ["ellipse(calc((75% + 960px) / 4) at 50% 50%)", "ellipse(calc(18.75% + 240px) at 50% 50%)"]
+FAIL ellipse(calc(25%*3 - 10in)) - computed style assert_in_array: value "ellipse(calc(75% + -960px) at 50% 50%)" not in array ["ellipse(calc(75% - 960px) at 50% 50%)", "ellipse(calc(-960px + 75%) at 50% 50%)"]
+PASS ellipse(calc((12.5%*6 + 10in) / 4)) - computed style
 PASS ellipse(farthest-side calc(10in)) - computed style
 PASS ellipse(farthest-side calc(10in + 20px)) - computed style
 PASS ellipse(farthest-side calc(30%)) - computed style
 PASS ellipse(farthest-side calc(100%/4)) - computed style
 PASS ellipse(farthest-side calc(25%*3)) - computed style
-PASS ellipse(farthest-side calc(25%*3 - 10in)) - computed style
-FAIL ellipse(farthest-side calc((12.5%*6 + 10in) / 4)) - computed style assert_in_array: value "ellipse(farthest-side calc(240px + 18.75%) at 50% 50%)" not in array ["ellipse(farthest-side calc((75% + 960px) / 4) at 50% 50%)", "ellipse(farthest-side calc(18.75% + 240px) at 50% 50%)"]
+FAIL ellipse(farthest-side calc(25%*3 - 10in)) - computed style assert_in_array: value "ellipse(farthest-side calc(75% + -960px) at 50% 50%)" not in array ["ellipse(farthest-side calc(75% - 960px) at 50% 50%)", "ellipse(farthest-side calc(-960px + 75%) at 50% 50%)"]
+PASS ellipse(farthest-side calc((12.5%*6 + 10in) / 4)) - computed style
 PASS ellipse(calc(10in) calc(10in)) - computed style
 PASS ellipse(calc(10in + 20px) calc(10in + 20px)) - computed style
 PASS ellipse(calc(30%) calc(30%)) - computed style
 PASS ellipse(calc(100%/4) calc(100%/4)) - computed style
 PASS ellipse(calc(25%*3) calc(25%*3)) - computed style
-PASS ellipse(calc(25%*3 - 10in) calc(25%*3 - 10in)) - computed style
-FAIL ellipse(calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4)) - computed style assert_in_array: value "ellipse(calc(240px + 18.75%) calc(240px + 18.75%) at 50% 50%)" not in array ["ellipse(calc((75% + 960px) / 4) calc((75% + 960px) / 4) at 50% 50%)", "ellipse(calc(18.75% + 240px) calc(18.75% + 240px) at 50% 50%)"]
+FAIL ellipse(calc(25%*3 - 10in) calc(25%*3 - 10in)) - computed style assert_in_array: value "ellipse(calc(75% + -960px) calc(75% + -960px) at 50% 50%)" not in array ["ellipse(calc(75% - 960px) calc(75% - 960px) at 50% 50%)", "ellipse(calc(-960px + 75%) calc(-960px + 75%) at 50% 50%)"]
+PASS ellipse(calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4)) - computed style
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-011-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-011-expected.txt
index 27a37189..ebe434e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-011-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-011-expected.txt
@@ -25,21 +25,21 @@
 PASS ellipse(at calc(30%) 50%) - computed style
 PASS ellipse(at calc(100%/4) 50%) - computed style
 PASS ellipse(at calc(25%*3) 50%) - computed style
-PASS ellipse(at calc(25%*3 - 10in) 50%) - computed style
-FAIL ellipse(at calc((12.5%*6 + 10in) / 4) 50%) - computed style assert_in_array: value "ellipse(at calc(240px + 18.75%) 50%)" not in array ["ellipse(at calc((75% + 960px) / 4) 50%)", "ellipse(at calc(18.75% + 240px) 50%)"]
+FAIL ellipse(at calc(25%*3 - 10in) 50%) - computed style assert_in_array: value "ellipse(at calc(75% + -960px) 50%)" not in array ["ellipse(at calc(75% - 960px) 50%)", "ellipse(at calc(-960px + 75%) 50%)"]
+PASS ellipse(at calc((12.5%*6 + 10in) / 4) 50%) - computed style
 PASS ellipse(farthest-side at calc(10in) 50%) - computed style
 PASS ellipse(farthest-side at calc(10in + 20px) 50%) - computed style
 PASS ellipse(farthest-side at calc(30%) 50%) - computed style
 PASS ellipse(farthest-side at calc(100%/4) 50%) - computed style
 PASS ellipse(farthest-side at calc(25%*3) 50%) - computed style
-PASS ellipse(farthest-side at calc(25%*3 - 10in) 50%) - computed style
-FAIL ellipse(farthest-side at calc((12.5%*6 + 10in) / 4) 50%) - computed style assert_in_array: value "ellipse(farthest-side at calc(240px + 18.75%) 50%)" not in array ["ellipse(farthest-side at calc((75% + 960px) / 4) 50%)", "ellipse(farthest-side at calc(18.75% + 240px) 50%)"]
+FAIL ellipse(farthest-side at calc(25%*3 - 10in) 50%) - computed style assert_in_array: value "ellipse(farthest-side at calc(75% + -960px) 50%)" not in array ["ellipse(farthest-side at calc(75% - 960px) 50%)", "ellipse(farthest-side at calc(-960px + 75%) 50%)"]
+PASS ellipse(farthest-side at calc((12.5%*6 + 10in) / 4) 50%) - computed style
 PASS ellipse(closest-side farthest-side at calc(10in) calc(10in)) - computed style
 PASS ellipse(closest-side farthest-side at calc(10in + 20px) calc(10in + 20px)) - computed style
 PASS ellipse(closest-side farthest-side at calc(30%) calc(30%)) - computed style
 PASS ellipse(closest-side farthest-side at calc(100%/4) calc(100%/4)) - computed style
 PASS ellipse(closest-side farthest-side at calc(25%*3) calc(25%*3)) - computed style
-PASS ellipse(closest-side farthest-side at calc(25%*3 - 10in) calc(25%*3 - 10in)) - computed style
-FAIL ellipse(closest-side farthest-side at calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4)) - computed style assert_in_array: value "ellipse(closest-side farthest-side at calc(240px + 18.75%) calc(240px + 18.75%))" not in array ["ellipse(closest-side farthest-side at calc((75% + 960px) / 4) calc((75% + 960px) / 4))", "ellipse(closest-side farthest-side at calc(18.75% + 240px) calc(18.75% + 240px))"]
+FAIL ellipse(closest-side farthest-side at calc(25%*3 - 10in) calc(25%*3 - 10in)) - computed style assert_in_array: value "ellipse(closest-side farthest-side at calc(75% + -960px) calc(75% + -960px))" not in array ["ellipse(closest-side farthest-side at calc(75% - 960px) calc(75% - 960px))", "ellipse(closest-side farthest-side at calc(-960px + 75%) calc(-960px + 75%))"]
+PASS ellipse(closest-side farthest-side at calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4)) - computed style
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-inset-008-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-inset-008-expected.txt
index 5f10cf9..b969e06 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-inset-008-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-inset-008-expected.txt
@@ -18,14 +18,14 @@
 PASS inset(calc(30%)) - computed style
 PASS inset(calc(100%/4)) - computed style
 PASS inset(calc(25%*3)) - computed style
-PASS inset(calc(25%*3 - 10in)) - computed style
-FAIL inset(calc((12.5%*6 + 10in) / 4)) - computed style assert_in_array: value "inset(calc(240px + 18.75%))" not in array ["inset(calc((75% + 960px) / 4))", "inset(calc(18.75% + 240px))"]
+FAIL inset(calc(25%*3 - 10in)) - computed style assert_in_array: value "inset(calc(75% + -960px))" not in array ["inset(calc(75% - 960px))", "inset(calc(-960px + 75%))"]
+PASS inset(calc((12.5%*6 + 10in) / 4)) - computed style
 PASS inset(calc(10in) calc(10in)) - computed style
 PASS inset(calc(10in + 20px) calc(10in + 20px)) - computed style
 PASS inset(calc(30%) calc(30%)) - computed style
 PASS inset(calc(100%/4) calc(100%/4)) - computed style
 PASS inset(calc(25%*3) calc(25%*3)) - computed style
-PASS inset(calc(25%*3 - 10in) calc(25%*3 - 10in)) - computed style
-FAIL inset(calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4)) - computed style assert_in_array: value "inset(calc(240px + 18.75%))" not in array ["inset(calc((75% + 960px) / 4))", "inset(calc(18.75% + 240px))"]
+FAIL inset(calc(25%*3 - 10in) calc(25%*3 - 10in)) - computed style assert_in_array: value "inset(calc(75% + -960px))" not in array ["inset(calc(75% - 960px))", "inset(calc(-960px + 75%))"]
+PASS inset(calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4)) - computed style
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-inset-009-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-inset-009-expected.txt
index 0d19e73d..4a38791 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-inset-009-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-inset-009-expected.txt
@@ -18,14 +18,14 @@
 PASS inset(10px 10px 10px 10px round calc(30%)) - computed style
 PASS inset(10px 10px 10px 10px round calc(100%/4)) - computed style
 PASS inset(10px 10px 10px 10px round calc(25%*3)) - computed style
-PASS inset(10px 10px 10px 10px round calc(25%*3 - 10in)) - computed style
-FAIL inset(10px 10px 10px 10px round calc((12.5%*6 + 10in) / 4)) - computed style assert_in_array: value "inset(10px round calc(240px + 18.75%))" not in array ["inset(10px round calc((75% + 960px) / 4))", "inset(10px round calc(18.75% + 240px))"]
+FAIL inset(10px 10px 10px 10px round calc(25%*3 - 10in)) - computed style assert_in_array: value "inset(10px round calc(75% + -960px))" not in array ["inset(10px round calc(75% - 960px))", "inset(10px round calc(-960px + 75%))"]
+PASS inset(10px 10px 10px 10px round calc((12.5%*6 + 10in) / 4)) - computed style
 PASS inset(10px 10px 10px 10px round calc(10in) calc(10in)) - computed style
 PASS inset(10px 10px 10px 10px round calc(10in + 20px) calc(10in + 20px)) - computed style
 PASS inset(10px 10px 10px 10px round calc(30%) calc(30%)) - computed style
 PASS inset(10px 10px 10px 10px round calc(100%/4) calc(100%/4)) - computed style
 PASS inset(10px 10px 10px 10px round calc(25%*3) calc(25%*3)) - computed style
-PASS inset(10px 10px 10px 10px round calc(25%*3 - 10in) calc(25%*3 - 10in)) - computed style
-FAIL inset(10px 10px 10px 10px round calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4)) - computed style assert_in_array: value "inset(10px round calc(240px + 18.75%))" not in array ["inset(10px round calc((75% + 960px) / 4))", "inset(10px round calc(18.75% + 240px))"]
+FAIL inset(10px 10px 10px 10px round calc(25%*3 - 10in) calc(25%*3 - 10in)) - computed style assert_in_array: value "inset(10px round calc(75% + -960px))" not in array ["inset(10px round calc(75% - 960px))", "inset(10px round calc(-960px + 75%))"]
+PASS inset(10px 10px 10px 10px round calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4)) - computed style
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-polygon-006-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-polygon-006-expected.txt
index 299a6712..f6747fa 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-polygon-006-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-polygon-006-expected.txt
@@ -18,14 +18,14 @@
 PASS polygon(calc(30%) calc(30%)) - computed style
 PASS polygon(calc(100%/4) calc(100%/4)) - computed style
 PASS polygon(calc(25%*3) calc(25%*3)) - computed style
-PASS polygon(calc(25%*3 - 10in) calc(25%*3 - 10in)) - computed style
-FAIL polygon(calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4)) - computed style assert_in_array: value "polygon(calc(240px + 18.75%) calc(240px + 18.75%))" not in array ["polygon(calc((75% + 960px) / 4) calc((75% + 960px) / 4))", "polygon(calc(18.75% + 240px) calc(18.75% + 240px))"]
+FAIL polygon(calc(25%*3 - 10in) calc(25%*3 - 10in)) - computed style assert_in_array: value "polygon(calc(75% + -960px) calc(75% + -960px))" not in array ["polygon(calc(75% - 960px) calc(75% - 960px))", "polygon(calc(-960px + 75%) calc(-960px + 75%))"]
+PASS polygon(calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4)) - computed style
 PASS polygon(evenodd, calc(10in) calc(10in), calc(10in) calc(10in)) - computed style
 PASS polygon(evenodd, calc(10in + 20px) calc(10in + 20px), calc(10in + 20px) calc(10in + 20px)) - computed style
 PASS polygon(evenodd, calc(30%) calc(30%), calc(30%) calc(30%)) - computed style
 PASS polygon(evenodd, calc(100%/4) calc(100%/4), calc(100%/4) calc(100%/4)) - computed style
 PASS polygon(evenodd, calc(25%*3) calc(25%*3), calc(25%*3) calc(25%*3)) - computed style
-PASS polygon(evenodd, calc(25%*3 - 10in) calc(25%*3 - 10in), calc(25%*3 - 10in) calc(25%*3 - 10in)) - computed style
-FAIL polygon(evenodd, calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4), calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4)) - computed style assert_in_array: value "polygon(evenodd, calc(240px + 18.75%) calc(240px + 18.75%), calc(240px + 18.75%) calc(240px + 18.75%))" not in array ["polygon(evenodd, calc((75% + 960px) / 4) calc((75% + 960px) / 4), calc((75% + 960px) / 4) calc((75% + 960px) / 4))", "polygon(evenodd, calc(18.75% + 240px) calc(18.75% + 240px), calc(18.75% + 240px) calc(18.75% + 240px))"]
+FAIL polygon(evenodd, calc(25%*3 - 10in) calc(25%*3 - 10in), calc(25%*3 - 10in) calc(25%*3 - 10in)) - computed style assert_in_array: value "polygon(evenodd, calc(75% + -960px) calc(75% + -960px), calc(75% + -960px) calc(75% + -960px))" not in array ["polygon(evenodd, calc(75% - 960px) calc(75% - 960px), calc(75% - 960px) calc(75% - 960px))", "polygon(evenodd, calc(-960px + 75%) calc(-960px + 75%), calc(-960px + 75%) calc(-960px + 75%))"]
+PASS polygon(evenodd, calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4), calc((12.5%*6 + 10in) / 4) calc((12.5%*6 + 10in) / 4)) - computed style
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/transforms-support-calc-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/transforms-support-calc-expected.txt
index f58ab6d..3e16e0c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/transforms-support-calc-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/transforms-support-calc-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-FAIL translate supports calc assert_equals: expected "calc(20% + 30px) calc(100% - 200px)" but got "calc(30px + 20%) calc(-200px + 100%)"
+FAIL translate supports calc assert_equals: expected "calc(20% + 30px) calc(100% - 200px)" but got "calc(20% + 30px) calc(100% + -200px)"
 PASS rotate supports calc
 PASS scale supports calc
 PASS perspective supports calc
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/translate-getComputedStyle.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/translate-getComputedStyle.html
index 1e6759d..46a2c309 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/translate-getComputedStyle.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/translate-getComputedStyle.html
@@ -42,7 +42,7 @@
     test(function() {
       assert_equals(getTranslateFor("first"), "10px 20px");
       assert_equals(getTranslateFor("second"), "30% 40% 50px");
-      assert_equals(getTranslateFor("third"), "calc(70px + 80%) -90px");
+      assert_equals(getTranslateFor("third"), "calc(80% + 70px) -90px");
     }, "computed style for translate");
   </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/motion/offset-supports-calc.html b/third_party/WebKit/LayoutTests/external/wpt/css/motion/offset-supports-calc.html
index 79aa9a9f..9ec737e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/motion/offset-supports-calc.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/motion/offset-supports-calc.html
@@ -22,7 +22,7 @@
 
 test(function(){
   target.style = 'offset-position: calc(30px + 20%) calc(-200px + 8em + 100%);';
-  assert_equals(getComputedStyle(target).offsetPosition, 'calc(30px + 20%) calc(-40px + 100%)');
+  assert_equals(getComputedStyle(target).offsetPosition, 'calc(20% + 30px) calc(100% + -40px)');
 }, 'offset-position supports calc');
 
 test(function(){
@@ -32,7 +32,7 @@
 
 test(function(){
   target.style = 'offset-distance: calc(-100px + 50%);';
-  assert_equals(getComputedStyle(target).offsetDistance, 'calc(-100px + 50%)');
+  assert_equals(getComputedStyle(target).offsetDistance, 'calc(50% + -100px)');
 }, 'offset-distance supports calc');
 
 test(function(){
@@ -42,7 +42,7 @@
 
 test(function(){
   target.style = 'offset-anchor: calc(30px + 20%) calc(-200px + 8em + 100%);';
-  assert_equals(getComputedStyle(target).offsetAnchor, 'calc(30px + 20%) calc(-40px + 100%)');
+  assert_equals(getComputedStyle(target).offsetAnchor, 'calc(20% + 30px) calc(100% + -40px)');
 }, 'offset-anchor supports calc');
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/custom-elements/CustomElementRegistry-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/custom-elements/CustomElementRegistry-expected.txt
new file mode 100644
index 0000000..daa93a4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/custom-elements/CustomElementRegistry-expected.txt
@@ -0,0 +1,40 @@
+This is a testharness.js-based test.
+PASS CustomElementRegistry interface must have define as a method
+PASS customElements.define must throw when the element interface is not a constructor
+PASS customElements.define must not throw the constructor is HTMLElement
+PASS customElements.define must throw with an invalid name
+PASS customElements.define must throw when there is already a custom element of the same name
+PASS customElements.define must throw a NotSupportedError when there is already a custom element with the same class
+PASS customElements.define must throw a NotSupportedError when element definition is running flag is set
+PASS customElements.define must check IsConstructor on the constructor before checking the element definition is running flag
+PASS customElements.define must validate the custom element name before checking the element definition is running flag
+PASS customElements.define unset the element definition is running flag before upgrading custom elements
+FAIL customElements.define must not throw when defining another custom element in a different global object during Get(constructor, "prototype") Failed to execute 'define' on 'CustomElementRegistry': this name has already been used with this registry
+PASS Custom Elements: CustomElementRegistry interface
+FAIL customElements.define must get "prototype" property of the constructor assert_array_equals: lengths differ, expected 1 got 2
+PASS customElements.define must rethrow an exception thrown while getting "prototype" property of the constructor
+PASS customElements.define must throw when "prototype" property of the constructor is not an object
+PASS customElements.define must get callbacks of the constructor prototype
+PASS customElements.define must rethrow an exception thrown while getting callbacks on the constructor prototype
+PASS customElements.define must rethrow an exception thrown while converting a callback value to Function callback type
+FAIL customElements.define must get "observedAttributes" property on the constructor prototype when "attributeChangedCallback" is present assert_array_equals: lengths differ, expected 4 got 6
+PASS customElements.define must rethrow an exception thrown while getting observedAttributes on the constructor prototype
+PASS customElements.define must rethrow an exception thrown while converting the value of observedAttributes to sequence<DOMString>
+PASS customElements.define must rethrow an exception thrown while iterating over observedAttributes to sequence<DOMString>
+PASS customElements.define must rethrow an exception thrown while retrieving Symbol.iterator on observedAttributes
+PASS customElements.define must not throw even if "observedAttributes" fails to convert if "attributeChangedCallback" is not defined
+PASS customElements.define must define an instantiatable custom element
+PASS customElements.define must upgrade elements in the shadow-including tree order
+PASS CustomElementRegistry interface must have get as a method
+PASS customElements.get must return undefined when the registry does not contain an entry with the given name
+PASS customElements.get must return undefined when the registry does not contain an entry with the given name even if the name was not a valid custom element name
+PASS customElements.get return the constructor of the entry with the given name when there is a matching entry.
+PASS customElements.whenDefined must return a promise for a valid custom element name
+PASS customElements.whenDefined must return the same promise each time invoked for a valid custom element name which has not been defined
+PASS customElements.whenDefined must return an unresolved promise when the registry does not contain the entry with the given name
+PASS customElements.whenDefined must return a rejected promise when the given name is not a valid custom element name
+PASS customElements.whenDefined must return a resolved promise when the registry contains the entry with the given name
+PASS customElements.whenDefined must return a new resolved promise each time invoked when the registry contains the entry with the given name
+PASS A promise returned by customElements.whenDefined must be resolved by "define"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/cx-computed-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/cx-computed-expected.txt
deleted file mode 100644
index 3bc668f7..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/cx-computed-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS Property cx value '-10px' computes to '-10px'
-PASS Property cx value '0.5em' computes to '20px'
-PASS Property cx value 'calc(10px + 0.5em)' computes to '30px'
-PASS Property cx value '40%' computes to '40%'
-FAIL Property cx value 'calc(50% + 60x)' computes to 'calc(50% + 60x)' assert_equals: expected "calc(50% + 60x)" but got "0px"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/cx-computed.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/cx-computed.svg
index 5a408ba4..95c39fa 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/cx-computed.svg
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/cx-computed.svg
@@ -20,8 +20,9 @@
 test_computed_value("cx", "-10px");
 test_computed_value("cx", "0.5em", "20px");
 test_computed_value("cx", "calc(10px + 0.5em)", "30px");
+test_computed_value("cx", "calc(10px - 0.5em)", "-10px");
 test_computed_value("cx", "40%");
-test_computed_value("cx", "calc(50% + 60x)");
+test_computed_value("cx", "calc(50% + 60px)");
 
   ]]></script>
 </svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/cy-computed-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/cy-computed-expected.txt
deleted file mode 100644
index 39247385..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/cy-computed-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS Property cy value '-10px' computes to '-10px'
-PASS Property cy value '0.5em' computes to '20px'
-PASS Property cy value 'calc(10px + 0.5em)' computes to '30px'
-PASS Property cy value '40%' computes to '40%'
-FAIL Property cy value 'calc(50% + 60x)' computes to 'calc(50% + 60x)' assert_equals: expected "calc(50% + 60x)" but got "0px"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/cy-computed.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/cy-computed.svg
index 97a41aed..23b56cb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/cy-computed.svg
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/cy-computed.svg
@@ -20,8 +20,9 @@
 test_computed_value("cy", "-10px");
 test_computed_value("cy", "0.5em", "20px");
 test_computed_value("cy", "calc(10px + 0.5em)", "30px");
+test_computed_value("cy", "calc(10px - 0.5em)", "-10px");
 test_computed_value("cy", "40%");
-test_computed_value("cy", "calc(50% + 60x)");
+test_computed_value("cy", "calc(50% + 60px)");
 
   ]]></script>
 </svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/r-computed-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/r-computed-expected.txt
deleted file mode 100644
index 06df88a..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/r-computed-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS Property r value '10px' computes to '10px'
-PASS Property r value '0.5em' computes to '20px'
-PASS Property r value 'calc(10px + 0.5em)' computes to '30px'
-PASS Property r value '40%' computes to '40%'
-FAIL Property r value 'calc(50% + 60x)' computes to 'calc(50% + 60x)' assert_equals: expected "calc(50% + 60x)" but got "0px"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/r-computed.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/r-computed.svg
index fc8ea98..b0f6bb0f67 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/r-computed.svg
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/r-computed.svg
@@ -20,8 +20,9 @@
 test_computed_value("r", "10px");
 test_computed_value("r", "0.5em", "20px");
 test_computed_value("r", "calc(10px + 0.5em)", "30px");
+test_computed_value("r", "calc(10px - 0.5em)", "0px");
 test_computed_value("r", "40%");
-test_computed_value("r", "calc(50% + 60x)");
+test_computed_value("r", "calc(50% + 60px)");
 
   ]]></script>
 </svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/rx-computed-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/rx-computed-expected.txt
deleted file mode 100644
index 4a74732..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/rx-computed-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-PASS Property rx value 'auto' computes to 'auto'
-PASS Property rx value '10px' computes to '10px'
-PASS Property rx value '0.5em' computes to '20px'
-PASS Property rx value 'calc(10px + 0.5em)' computes to '30px'
-PASS Property rx value '40%' computes to '40%'
-FAIL Property rx value 'calc(50% + 60x)' computes to 'calc(50% + 60x)' assert_equals: expected "calc(50% + 60x)" but got "auto"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/rx-computed.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/rx-computed.svg
index 7e4c42d2..a321080 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/rx-computed.svg
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/rx-computed.svg
@@ -22,8 +22,9 @@
 test_computed_value("rx", "10px");
 test_computed_value("rx", "0.5em", "20px");
 test_computed_value("rx", "calc(10px + 0.5em)", "30px");
+test_computed_value("rx", "calc(10px - 0.5em)", "0px");
 test_computed_value("rx", "40%");
-test_computed_value("rx", "calc(50% + 60x)");
+test_computed_value("rx", "calc(50% + 60px)");
 
   ]]></script>
 </svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/ry-computed-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/ry-computed-expected.txt
deleted file mode 100644
index d4cfd52..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/ry-computed-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-PASS Property ry value 'auto' computes to 'auto'
-PASS Property ry value '10px' computes to '10px'
-PASS Property ry value '0.5em' computes to '20px'
-PASS Property ry value 'calc(10px + 0.5em)' computes to '30px'
-PASS Property ry value '40%' computes to '40%'
-FAIL Property ry value 'calc(50% + 60x)' computes to 'calc(50% + 60x)' assert_equals: expected "calc(50% + 60x)" but got "auto"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/ry-computed.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/ry-computed.svg
index 390d63d..b274199 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/ry-computed.svg
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/ry-computed.svg
@@ -22,8 +22,9 @@
 test_computed_value("ry", "10px");
 test_computed_value("ry", "0.5em", "20px");
 test_computed_value("ry", "calc(10px + 0.5em)", "30px");
+test_computed_value("ry", "calc(10px - 0.5em)", "0px");
 test_computed_value("ry", "40%");
-test_computed_value("ry", "calc(50% + 60x)");
+test_computed_value("ry", "calc(50% + 60px)");
 
   ]]></script>
 </svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/x-computed-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/x-computed-expected.txt
deleted file mode 100644
index b7b5a0d..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/x-computed-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS Property x value '-10px' computes to '-10px'
-PASS Property x value '0.5em' computes to '20px'
-PASS Property x value 'calc(10px + 0.5em)' computes to '30px'
-PASS Property x value '40%' computes to '40%'
-FAIL Property x value 'calc(50% + 60x)' computes to 'calc(50% + 60x)' assert_equals: expected "calc(50% + 60x)" but got "0px"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/x-computed.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/x-computed.svg
index f7da0ed..9355ea3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/x-computed.svg
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/x-computed.svg
@@ -20,8 +20,9 @@
 test_computed_value("x", "-10px");
 test_computed_value("x", "0.5em", "20px");
 test_computed_value("x", "calc(10px + 0.5em)", "30px");
+test_computed_value("x", "calc(10px - 0.5em)", "-10px");
 test_computed_value("x", "40%");
-test_computed_value("x", "calc(50% + 60x)");
+test_computed_value("x", "calc(50% + 60px)");
 
   ]]></script>
 </svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/y-computed-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/y-computed-expected.txt
deleted file mode 100644
index 71c245f..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/y-computed-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS Property y value '-10px' computes to '-10px'
-PASS Property y value '0.5em' computes to '20px'
-PASS Property y value 'calc(10px + 0.5em)' computes to '30px'
-PASS Property y value '40%' computes to '40%'
-FAIL Property y value 'calc(50% + 60x)' computes to 'calc(50% + 60x)' assert_equals: expected "calc(50% + 60x)" but got "0px"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/y-computed.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/y-computed.svg
index 83ef887..6c425e4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/y-computed.svg
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/geometry/parsing/y-computed.svg
@@ -20,8 +20,9 @@
 test_computed_value("y", "-10px");
 test_computed_value("y", "0.5em", "20px");
 test_computed_value("y", "calc(10px + 0.5em)", "30px");
+test_computed_value("y", "calc(10px - 0.5em)", "-10px");
 test_computed_value("y", "40%");
-test_computed_value("y", "calc(50% + 60x)");
+test_computed_value("y", "calc(50% + 60px)");
 
   ]]></script>
 </svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/painting/parsing/stroke-width-computed.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/painting/parsing/stroke-width-computed.svg
new file mode 100644
index 0000000..c9284be
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/painting/parsing/stroke-width-computed.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:h="http://www.w3.org/1999/xhtml"
+     width="800px" height="800px">
+  <title>SVG Geometry Properties: getComputedValue().strokeWidth</title>
+  <metadata>
+    <h:link rel="help" href="https://svgwg.org/svg2-draft/painting.html#StrokeWidth"/>
+  </metadata>
+  <g id="target"></g>
+  <style>
+    #target {
+      font-size: 40px;
+    }
+  </style>
+  <h:script src="/resources/testharness.js"/>
+  <h:script src="/resources/testharnessreport.js"/>
+  <h:script src="/css/support/computed-testcommon.js"/>
+  <script><![CDATA[
+
+test_computed_value("stroke-width", "10", "10px");
+test_computed_value("stroke-width", "calc(10px + 0.5em)", "30px");
+test_computed_value("stroke-width", "calc(10px - 0.5em)", "0px");
+test_computed_value("stroke-width", "40%");
+test_computed_value("stroke-width", "calc(50% + 60px)");
+
+  ]]></script>
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/painting/parsing/stroke-width-valid.svg b/third_party/WebKit/LayoutTests/external/wpt/svg/painting/parsing/stroke-width-valid.svg
index 312b892..02bca18 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/painting/parsing/stroke-width-valid.svg
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/painting/parsing/stroke-width-valid.svg
@@ -19,6 +19,7 @@
 test_valid_value("stroke-width", "calc(2em + 3ex)");
 test_valid_value("stroke-width", "4%");
 test_valid_value("stroke-width", "5vmin");
+test_valid_value("stroke-width", "calc(50% + 60px)");
 
   ]]></script>
 </svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/accumulation-per-property-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/accumulation-per-property-expected.txt
index 949315d..27a349b10 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/accumulation-per-property-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/accumulation-per-property-expected.txt
@@ -216,14 +216,14 @@
 PASS flex-basis: length
 PASS flex-basis: length of rem
 PASS flex-basis: percentage
-FAIL flex-basis: units "%" onto "px" assert_equals: The value should be calc(10px + 10%) at 0ms expected "calc(10px + 10%)" but got "10%"
-FAIL flex-basis: units "px" onto "%" assert_equals: The value should be calc(10px + 10%) at 0ms expected "calc(10px + 10%)" but got "10px"
-FAIL flex-basis: units "rem" onto "%" assert_equals: The value should be calc(20px + 10%) at 0ms expected "calc(20px + 10%)" but got "20px"
-FAIL flex-basis: units "%" onto "rem" assert_equals: The value should be calc(20px + 10%) at 0ms expected "calc(20px + 10%)" but got "10%"
+FAIL flex-basis: units "%" onto "px" assert_equals: The value should be calc(10% + 10px) at 0ms expected "calc(10% + 10px)" but got "10%"
+FAIL flex-basis: units "px" onto "%" assert_equals: The value should be calc(10% + 10px) at 0ms expected "calc(10% + 10px)" but got "10px"
+FAIL flex-basis: units "rem" onto "%" assert_equals: The value should be calc(10% + 20px) at 0ms expected "calc(10% + 20px)" but got "20px"
+FAIL flex-basis: units "%" onto "rem" assert_equals: The value should be calc(10% + 20px) at 0ms expected "calc(10% + 20px)" but got "10%"
 FAIL flex-basis: units "rem" onto "em" assert_equals: The value should be 40px at 0ms expected "40px" but got "20px"
 FAIL flex-basis: units "em" onto "rem" assert_equals: The value should be 40px at 0ms expected "40px" but got "20px"
-FAIL flex-basis: units "calc" onto "px" assert_equals: The value should be calc(30px + 20%) at 0ms expected "calc(30px + 20%)" but got "calc(20px + 20%)"
-FAIL flex-basis: calc assert_equals: The value should be calc(30px + 30%) at 0ms expected "calc(30px + 30%)" but got "calc(20px + 20%)"
+FAIL flex-basis: units "calc" onto "px" assert_equals: The value should be calc(20% + 30px) at 0ms expected "calc(20% + 30px)" but got "calc(20% + 20px)"
+FAIL flex-basis: calc assert_equals: The value should be calc(30% + 30px) at 0ms expected "calc(30% + 30px)" but got "calc(20% + 20px)"
 PASS flex-basis (type: discrete) has testAccumulation function
 PASS flex-basis: "10px" onto "auto"
 PASS flex-basis: "auto" onto "10px"
@@ -558,13 +558,13 @@
 PASS word-spacing: length
 PASS word-spacing: length of rem
 FAIL word-spacing: percentage assert_equals: The value should be 130% at 0ms expected "130%" but got "0px"
-FAIL word-spacing: units "%" onto "px" assert_equals: The value should be calc(10px + 10%) at 0ms expected "calc(10px + 10%)" but got "10px"
-FAIL word-spacing: units "px" onto "%" assert_equals: The value should be calc(10px + 10%) at 0ms expected "calc(10px + 10%)" but got "10px"
-FAIL word-spacing: units "rem" onto "%" assert_equals: The value should be calc(20px + 10%) at 0ms expected "calc(20px + 10%)" but got "20px"
-FAIL word-spacing: units "%" onto "rem" assert_equals: The value should be calc(20px + 10%) at 0ms expected "calc(20px + 10%)" but got "20px"
+FAIL word-spacing: units "%" onto "px" assert_equals: The value should be calc(10% + 10px) at 0ms expected "calc(10% + 10px)" but got "10px"
+FAIL word-spacing: units "px" onto "%" assert_equals: The value should be calc(10% + 10px) at 0ms expected "calc(10% + 10px)" but got "10px"
+FAIL word-spacing: units "rem" onto "%" assert_equals: The value should be calc(10% + 20px) at 0ms expected "calc(10% + 20px)" but got "20px"
+FAIL word-spacing: units "%" onto "rem" assert_equals: The value should be calc(10% + 20px) at 0ms expected "calc(10% + 20px)" but got "20px"
 FAIL word-spacing: units "rem" onto "em" assert_equals: The value should be 40px at 0ms expected "40px" but got "20px"
 FAIL word-spacing: units "em" onto "rem" assert_equals: The value should be 40px at 0ms expected "40px" but got "20px"
-FAIL word-spacing: units "calc" onto "px" assert_equals: The value should be calc(30px + 20%) at 0ms expected "calc(30px + 20%)" but got "10px"
-FAIL word-spacing: calc assert_equals: The value should be calc(30px + 30%) at 0ms expected "calc(30px + 30%)" but got "0px"
+FAIL word-spacing: units "calc" onto "px" assert_equals: The value should be calc(20% + 30px) at 0ms expected "calc(20% + 30px)" but got "10px"
+FAIL word-spacing: calc assert_equals: The value should be calc(30% + 30px) at 0ms expected "calc(30% + 30px)" but got "0px"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/addition-per-property-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/addition-per-property-expected.txt
index 482d537..75190da 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/addition-per-property-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/addition-per-property-expected.txt
@@ -449,7 +449,7 @@
 PASS stop-opacity: [0, 1] number
 PASS stop-opacity: [0, 1] number (clamped)
 PASS stroke-dasharray (type: dasharray) has testAddition function
-FAIL stroke-dasharray: dasharray assert_equals: The value should be 1, 2, 3, 4, 5 at 0ms expected "1, 2, 3, 4, 5" but got "7px, calc(2px + 30%), 5px, 10px, calc(5px + 30%), 3px, 8px, calc(3px + 30%), 6px, 11px, calc(1px + 30%), 4px, 9px, calc(4px + 30%), 7px"
+FAIL stroke-dasharray: dasharray assert_equals: The value should be 1, 2, 3, 4, 5 at 0ms expected "1, 2, 3, 4, 5" but got "7px, calc(30% + 2px), 5px, 10px, calc(30% + 5px), 3px, 8px, calc(30% + 3px), 6px, 11px, calc(30% + 1px), 4px, 9px, calc(30% + 4px), 7px"
 PASS stroke-dasharray (type: discrete) has testAddition function
 FAIL stroke-dasharray: "10, 20" onto "none" assert_equals: The value should be 10, 20 at 0ms expected "10, 20" but got "10px, 20px"
 PASS stroke-dasharray: "none" onto "10, 20"
@@ -533,7 +533,7 @@
 PASS translate (type: translateList) has testAddition function
 PASS translate
 PASS translate with underlying transform
-FAIL translate with underlying percentage value assert_equals: The value should be calc(50% - 200px) at 0ms expected "calc(50% - 200px)" but got "calc(-200px + 50%)"
+FAIL translate with underlying percentage value assert_equals: The value should be calc(50% - 200px) at 0ms expected "calc(50% - 200px)" but got "calc(50% + -200px)"
 PASS scale (type: scaleList) has testAddition function
 FAIL scale with two unspecified values assert_equals: The value should be -6 at 0ms expected "-6" but got "-6 2"
 FAIL scale with one unspecified value assert_equals: The value should be -6 at 0ms expected "-6" but got "-6 -6"
@@ -554,13 +554,13 @@
 PASS word-spacing: length
 PASS word-spacing: length of rem
 FAIL word-spacing: percentage assert_equals: The value should be 130% at 0ms expected "130%" but got "0px"
-FAIL word-spacing: units "%" onto "px" assert_equals: The value should be calc(10px + 10%) at 0ms expected "calc(10px + 10%)" but got "10px"
-FAIL word-spacing: units "px" onto "%" assert_equals: The value should be calc(10px + 10%) at 0ms expected "calc(10px + 10%)" but got "10px"
-FAIL word-spacing: units "rem" onto "%" assert_equals: The value should be calc(20px + 10%) at 0ms expected "calc(20px + 10%)" but got "20px"
-FAIL word-spacing: units "%" onto "rem" assert_equals: The value should be calc(20px + 10%) at 0ms expected "calc(20px + 10%)" but got "20px"
+FAIL word-spacing: units "%" onto "px" assert_equals: The value should be calc(10% + 10px) at 0ms expected "calc(10% + 10px)" but got "10px"
+FAIL word-spacing: units "px" onto "%" assert_equals: The value should be calc(10% + 10px) at 0ms expected "calc(10% + 10px)" but got "10px"
+FAIL word-spacing: units "rem" onto "%" assert_equals: The value should be calc(10% + 20px) at 0ms expected "calc(10% + 20px)" but got "20px"
+FAIL word-spacing: units "%" onto "rem" assert_equals: The value should be calc(10% + 20px) at 0ms expected "calc(10% + 20px)" but got "20px"
 PASS word-spacing: units "rem" onto "em"
 PASS word-spacing: units "em" onto "rem"
-FAIL word-spacing: units "calc" onto "px" assert_equals: The value should be calc(30px + 20%) at 0ms expected "calc(30px + 20%)" but got "10px"
-FAIL word-spacing: calc assert_equals: The value should be calc(30px + 30%) at 0ms expected "calc(30px + 30%)" but got "0px"
+FAIL word-spacing: units "calc" onto "px" assert_equals: The value should be calc(20% + 30px) at 0ms expected "calc(20% + 30px)" but got "10px"
+FAIL word-spacing: calc assert_equals: The value should be calc(30% + 30px) at 0ms expected "calc(30% + 30px)" but got "0px"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/interpolation-per-property-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/interpolation-per-property-expected.txt
index 6a24e5f4..afd0cfa 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/interpolation-per-property-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/interpolation-per-property-expected.txt
@@ -670,7 +670,7 @@
 PASS translate with two unspecified values
 PASS translate with one unspecified value
 PASS translate with all three values specified
-FAIL translate with combination of percentages and lengths assert_equals: The value should be 200px calc(25% - 50.5px) 200px at 500ms expected "200px calc(25% - 50.5px) 200px" but got "200px calc(-50.5px + 25%) 200px"
+FAIL translate with combination of percentages and lengths assert_equals: The value should be 200px calc(25% - 50.5px) 200px at 500ms expected "200px calc(25% - 50.5px) 200px" but got "200px calc(25% + -50.5px) 200px"
 PASS scale (type: scaleList) has testInterpolation function
 FAIL scale with two unspecified values assert_equals: The value should be 4 at 500ms expected "4" but got "4 1"
 FAIL scale with one unspecified value assert_equals: The value should be 4 at 500ms expected "4" but got "4 4"
@@ -696,10 +696,10 @@
 PASS word-spacing supports animating as a length
 PASS word-spacing supports animating as a length of rem
 FAIL word-spacing supports animating as a percentage assert_equals: The value should be 30% at 500ms expected "30%" but got "0px"
-FAIL word-spacing supports animating as combination units "px" and "%" assert_equals: The value should be calc(5px + 10%) at 500ms expected "calc(5px + 10%)" but got "5px"
-FAIL word-spacing supports animating as combination units "%" and "em" assert_equals: The value should be calc(10px + 5%) at 500ms expected "calc(10px + 5%)" but got "10px"
+FAIL word-spacing supports animating as combination units "px" and "%" assert_equals: The value should be calc(10% + 5px) at 500ms expected "calc(10% + 5px)" but got "5px"
+FAIL word-spacing supports animating as combination units "%" and "em" assert_equals: The value should be calc(5% + 10px) at 500ms expected "calc(5% + 10px)" but got "10px"
 PASS word-spacing supports animating as combination units "em" and "rem"
-FAIL word-spacing supports animating as combination units "px" and "calc" assert_equals: The value should be calc(10px + 10%) at 500ms expected "calc(10px + 10%)" but got "5px"
-FAIL word-spacing supports animating as a calc assert_equals: The value should be calc(15px + 15%) at 500ms expected "calc(15px + 15%)" but got "0px"
+FAIL word-spacing supports animating as combination units "px" and "calc" assert_equals: The value should be calc(10% + 10px) at 500ms expected "calc(10% + 10px)" but got "5px"
+FAIL word-spacing supports animating as a calc assert_equals: The value should be calc(15% + 15px) at 500ms expected "calc(15% + 15px)" but got "0px"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/property-types.js b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/property-types.js
index 519e38ae..9382c629 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/property-types.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/animation-types/property-types.js
@@ -334,7 +334,7 @@
       const animation = target.animate({ [idlName]: ['10px', '20%'] },
                                        { duration: 1000, fill: 'both' });
       testAnimationSamples(animation, idlName,
-                           [{ time: 500,  expected: 'calc(5px + 10%)' }]);
+                           [{ time: 500,  expected: 'calc(10% + 5px)' }]);
     }, `${property} supports animating as combination units "px" and "%"`);
 
     test(t => {
@@ -343,7 +343,7 @@
       const animation = target.animate({ [idlName]: ['10%', '2em'] },
                                        { duration: 1000, fill: 'both' });
       testAnimationSamples(animation, idlName,
-                           [{ time: 500,  expected: 'calc(10px + 5%)' }]);
+                           [{ time: 500,  expected: 'calc(5% + 10px)' }]);
     }, `${property} supports animating as combination units "%" and "em"`);
 
     test(t => {
@@ -363,7 +363,7 @@
         { duration: 1000, fill: 'both' }
       );
       testAnimationSamples(animation, idlName,
-                           [{ time: 500,  expected: 'calc(10px + 10%)' }]);
+                           [{ time: 500,  expected: 'calc(10% + 10px)' }]);
     }, `${property} supports animating as combination units "px" and "calc"`);
 
     test(t => {
@@ -374,7 +374,7 @@
         { duration: 1000, fill: 'both' });
       testAnimationSamples(animation, idlName,
                            [{ time: 500,
-                              expected: 'calc(15px + 15%)' }]);
+                              expected: 'calc(15% + 15px)' }]);
     }, `${property} supports animating as a calc`);
   },
 
@@ -389,7 +389,7 @@
       const animation = target.animate({ [idlName]: ['10%', '50%'] },
                                        { duration: 1000, composite });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0, expected: 'calc(10px + 10%)' }]);
+                           [{ time: 0, expected: 'calc(10% + 10px)' }]);
     }, `${property}: units "%" onto "px"`);
 
     test(t => {
@@ -399,7 +399,7 @@
       const animation = target.animate({ [idlName]: ['10px', '50px'] },
                                        { duration: 1000, composite });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0, expected: 'calc(10px + 10%)' }]);
+                           [{ time: 0, expected: 'calc(10% + 10px)' }]);
     }, `${property}: units "px" onto "%"`);
 
     test(t => {
@@ -409,7 +409,7 @@
       const animation = target.animate({ [idlName]: ['2rem', '5rem'] },
                                        { duration: 1000, composite });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0, expected: 'calc(20px + 10%)' }]);
+                           [{ time: 0, expected: 'calc(10% + 20px)' }]);
     }, `${property}: units "rem" onto "%"`);
 
     test(t => {
@@ -419,7 +419,7 @@
       const animation = target.animate({ [idlName]: ['10%', '50%'] },
                                        { duration: 1000, composite });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0, expected: 'calc(20px + 10%)' }]);
+                           [{ time: 0, expected: 'calc(10% + 20px)' }]);
     }, `${property}: units "%" onto "rem"`);
 
     test(t => {
@@ -448,7 +448,7 @@
                                                    'calc(5rem + 50%)'] },
                                        { duration: 1000, composite });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0, expected: 'calc(30px + 20%)' }]);
+                           [{ time: 0, expected: 'calc(20% + 30px)' }]);
     }, `${property}: units "calc" onto "px"`);
 
     test(t => {
@@ -459,7 +459,7 @@
                                                    'calc(2em + 3rem + 40%)'] },
                                        { duration: 1000, composite });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0, expected: 'calc(30px + 30%)' }]);
+                           [{ time: 0, expected: 'calc(30% + 30px)' }]);
     }, `${property}: calc`);
   },
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc-quic/META.yml b/third_party/WebKit/LayoutTests/external/wpt/webrtc-quic/META.yml
new file mode 100644
index 0000000..740c8d2f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc-quic/META.yml
@@ -0,0 +1,5 @@
+spec: https://github.com/w3c/webrtc-quic
+suggested_reviewers:
+  - aboba
+  - henbos
+  - steveanton
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCQuicStream-helper.js b/third_party/WebKit/LayoutTests/external/wpt/webrtc-quic/RTCQuicStream-helper.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCQuicStream-helper.js
rename to third_party/WebKit/LayoutTests/external/wpt/webrtc-quic/RTCQuicStream-helper.js
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCQuicStream.https.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc-quic/RTCQuicStream.https.html
similarity index 99%
rename from third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCQuicStream.https.html
rename to third_party/WebKit/LayoutTests/external/wpt/webrtc-quic/RTCQuicStream.https.html
index d7bed6da..08c3a54a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCQuicStream.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc-quic/RTCQuicStream.https.html
@@ -3,7 +3,7 @@
 <title>RTCQuicStream.https.html</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="RTCIceTransport-extension-helper.js"></script>
+<script src="../webrtc/RTCIceTransport-extension-helper.js"></script>
 <script src="RTCQuicTransport-helper.js"></script>
 <script src="RTCQuicStream-helper.js"></script>
 <script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCQuicTransport-helper.js b/third_party/WebKit/LayoutTests/external/wpt/webrtc-quic/RTCQuicTransport-helper.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCQuicTransport-helper.js
rename to third_party/WebKit/LayoutTests/external/wpt/webrtc-quic/RTCQuicTransport-helper.js
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCQuicTransport.https.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc-quic/RTCQuicTransport.https.html
similarity index 98%
rename from third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCQuicTransport.https.html
rename to third_party/WebKit/LayoutTests/external/wpt/webrtc-quic/RTCQuicTransport.https.html
index 3bcc93d..081f0b4d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCQuicTransport.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc-quic/RTCQuicTransport.https.html
@@ -3,7 +3,7 @@
 <title>RTCQuicTransport.https.html</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="RTCIceTransport-extension-helper.js"></script>
+<script src="../webrtc/RTCIceTransport-extension-helper.js"></script>
 <script src="RTCQuicTransport-helper.js"></script>
 <script>
 'use strict';
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/non-grid-columns-rows-get-set-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/non-grid-columns-rows-get-set-expected.txt
index 51c3ea8..b622d08f 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/non-grid-columns-rows-get-set-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/non-grid-columns-rows-get-set-expected.txt
@@ -25,12 +25,12 @@
 PASS window.getComputedStyle(gridWithFraction, '').getPropertyValue('grid-template-rows') is "2fr"
 PASS window.getComputedStyle(gridWithCalc, '').getPropertyValue('grid-template-columns') is "150px"
 PASS window.getComputedStyle(gridWithCalc, '').getPropertyValue('grid-template-rows') is "75px"
-PASS window.getComputedStyle(gridWithCalcComplex, '').getPropertyValue('grid-template-columns') is "calc(150px + 50%)"
-PASS window.getComputedStyle(gridWithCalcComplex, '').getPropertyValue('grid-template-rows') is "calc(75px + 65%)"
+PASS window.getComputedStyle(gridWithCalcComplex, '').getPropertyValue('grid-template-columns') is "calc(50% + 150px)"
+PASS window.getComputedStyle(gridWithCalcComplex, '').getPropertyValue('grid-template-rows') is "calc(65% + 75px)"
 PASS window.getComputedStyle(gridWithCalcInsideMinMax, '').getPropertyValue('grid-template-columns') is "minmax(10%, 15px)"
 PASS window.getComputedStyle(gridWithCalcInsideMinMax, '').getPropertyValue('grid-template-rows') is "minmax(20px, 50%)"
-PASS window.getComputedStyle(gridWithCalcComplexInsideMinMax, '').getPropertyValue('grid-template-columns') is "minmax(10%, calc(15px + 50%))"
-PASS window.getComputedStyle(gridWithCalcComplexInsideMinMax, '').getPropertyValue('grid-template-rows') is "minmax(calc(20px + 10%), 50%)"
+PASS window.getComputedStyle(gridWithCalcComplexInsideMinMax, '').getPropertyValue('grid-template-columns') is "minmax(10%, calc(50% + 15px))"
+PASS window.getComputedStyle(gridWithCalcComplexInsideMinMax, '').getPropertyValue('grid-template-rows') is "minmax(calc(10% + 20px), 50%)"
 PASS window.getComputedStyle(gridWithAutoInsideMinMax, '').getPropertyValue('grid-template-columns') is "minmax(auto, 20px)"
 PASS window.getComputedStyle(gridWithAutoInsideMinMax, '').getPropertyValue('grid-template-rows') is "minmax(min-content, auto)"
 
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/non-grid-columns-rows-get-set-multiple-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/non-grid-columns-rows-get-set-multiple-expected.txt
index 2b8daa1e..04f9f3b 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/non-grid-columns-rows-get-set-multiple-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/non-grid-columns-rows-get-set-multiple-expected.txt
@@ -31,10 +31,10 @@
 PASS window.getComputedStyle(gridWithCalcCalc, '').getPropertyValue('grid-template-rows') is "150px 75px"
 PASS window.getComputedStyle(gridWithCalcAndFixed, '').getPropertyValue('grid-template-columns') is "50% 80px"
 PASS window.getComputedStyle(gridWithCalcAndFixed, '').getPropertyValue('grid-template-rows') is "88px 25%"
-PASS window.getComputedStyle(gridWithCalcAndMinMax, '').getPropertyValue('grid-template-columns') is "calc(30px + 20%) minmax(min-content, 80px)"
-PASS window.getComputedStyle(gridWithCalcAndMinMax, '').getPropertyValue('grid-template-rows') is "minmax(25%, max-content) calc(-7px + 10%)"
-PASS window.getComputedStyle(gridWithCalcInsideMinMax, '').getPropertyValue('grid-template-columns') is "minmax(calc(23px + 10%), 400px) 120px"
-PASS window.getComputedStyle(gridWithCalcInsideMinMax, '').getPropertyValue('grid-template-rows') is "150px minmax(5%, calc(-125px + 50%))"
+PASS window.getComputedStyle(gridWithCalcAndMinMax, '').getPropertyValue('grid-template-columns') is "calc(20% + 30px) minmax(min-content, 80px)"
+PASS window.getComputedStyle(gridWithCalcAndMinMax, '').getPropertyValue('grid-template-rows') is "minmax(25%, max-content) calc(10% + -7px)"
+PASS window.getComputedStyle(gridWithCalcInsideMinMax, '').getPropertyValue('grid-template-columns') is "minmax(calc(10% + 23px), 400px) 120px"
+PASS window.getComputedStyle(gridWithCalcInsideMinMax, '').getPropertyValue('grid-template-rows') is "150px minmax(5%, calc(50% + -125px))"
 PASS window.getComputedStyle(gridWithAutoInsideMinMax, '').getPropertyValue('grid-template-columns') is "minmax(auto, 20px) 10%"
 PASS window.getComputedStyle(gridWithAutoInsideMinMax, '').getPropertyValue('grid-template-rows') is "max-content minmax(min-content, auto)"
 
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/non-grid-columns-rows-get-set-multiple.js b/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/non-grid-columns-rows-get-set-multiple.js
index e3f35fc..f17f76f5 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/non-grid-columns-rows-get-set-multiple.js
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/non-grid-columns-rows-get-set-multiple.js
@@ -15,8 +15,8 @@
 testGridDefinitionsValues(document.getElementById("gridWithFractionMinMax"), "minmax(min-content, 45px) 2fr", "3fr minmax(14px, max-content)");
 testGridDefinitionsValues(document.getElementById("gridWithCalcCalc"), "200px 100px", "150px 75px");
 testGridDefinitionsValues(document.getElementById("gridWithCalcAndFixed"), "50% 80px", "88px 25%");
-testGridDefinitionsValues(document.getElementById("gridWithCalcAndMinMax"), "calc(30px + 20%) minmax(min-content, 80px)", "minmax(25%, max-content) calc(-7px + 10%)");
-testGridDefinitionsValues(document.getElementById("gridWithCalcInsideMinMax"), "minmax(calc(23px + 10%), 400px) 120px", "150px minmax(5%, calc(-125px + 50%))");
+testGridDefinitionsValues(document.getElementById("gridWithCalcAndMinMax"), "calc(20% + 30px) minmax(min-content, 80px)", "minmax(25%, max-content) calc(10% + -7px)");
+testGridDefinitionsValues(document.getElementById("gridWithCalcInsideMinMax"), "minmax(calc(10% + 23px), 400px) 120px", "150px minmax(5%, calc(50% + -125px))");
 testGridDefinitionsValues(document.getElementById("gridWithAutoInsideMinMax"), "minmax(auto, 20px) 10%", "max-content minmax(min-content, auto)");
 
 debug("");
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/non-grid-columns-rows-get-set.js b/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/non-grid-columns-rows-get-set.js
index 26f2dbc..4013f739 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/non-grid-columns-rows-get-set.js
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/resources/non-grid-columns-rows-get-set.js
@@ -12,9 +12,9 @@
 testGridDefinitionsValues(document.getElementById("gridWithMaxContent"), "max-content", "max-content");
 testGridDefinitionsValues(document.getElementById("gridWithFraction"), "1fr", "2fr");
 testGridDefinitionsValues(document.getElementById("gridWithCalc"), "150px", "75px");
-testGridDefinitionsValues(document.getElementById("gridWithCalcComplex"), "calc(150px + 50%)", "calc(75px + 65%)");
+testGridDefinitionsValues(document.getElementById("gridWithCalcComplex"), "calc(50% + 150px)", "calc(65% + 75px)");
 testGridDefinitionsValues(document.getElementById("gridWithCalcInsideMinMax"), "minmax(10%, 15px)", "minmax(20px, 50%)");
-testGridDefinitionsValues(document.getElementById("gridWithCalcComplexInsideMinMax"), "minmax(10%, calc(15px + 50%))", "minmax(calc(20px + 10%), 50%)");
+testGridDefinitionsValues(document.getElementById("gridWithCalcComplexInsideMinMax"), "minmax(10%, calc(50% + 15px))", "minmax(calc(10% + 20px), 50%)");
 testGridDefinitionsValues(document.getElementById("gridWithAutoInsideMinMax"), "minmax(auto, 20px)", "minmax(min-content, auto)");
 
 debug("");
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-background-position-calc-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-background-position-calc-expected.txt
index c75dcf5..0bf843b 100644
--- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-background-position-calc-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-background-position-calc-expected.txt
@@ -1,3 +1,3 @@
 Test calling on background-position property specified with calc on computed styles.
 
-left calc(20px + 10%) bottom calc(30px + 40%)
+left calc(10% + 20px) bottom calc(40% + 30px)
diff --git a/third_party/WebKit/LayoutTests/fast/css/parsing-object-position-expected.txt b/third_party/WebKit/LayoutTests/fast/css/parsing-object-position-expected.txt
index b8c2669..ca387d6a 100644
--- a/third_party/WebKit/LayoutTests/fast/css/parsing-object-position-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css/parsing-object-position-expected.txt
@@ -9,7 +9,7 @@
 PASS testComputedStyle("object-position: top right;") is "100% 0%"
 PASS testComputedStyle("object-position: left 20px bottom 50%;") is "20px 50%"
 PASS testComputedStyle("object-position: right 50% bottom 25%;") is "50% 75%"
-PASS testComputedStyle("object-position: bottom 20px right 12px;") is "calc(-12px + 100%) calc(-20px + 100%)"
+PASS testComputedStyle("object-position: bottom 20px right 12px;") is "calc(100% + -12px) calc(100% + -20px)"
 PASS test("object-position: inherit;") is "inherit"
 PASS test("object-position: initial;") is "initial"
 PASS test("object-position: left;") is "left center"
diff --git a/third_party/WebKit/LayoutTests/fast/css/parsing-object-position.html b/third_party/WebKit/LayoutTests/fast/css/parsing-object-position.html
index ebabba6e..78c257b 100644
--- a/third_party/WebKit/LayoutTests/fast/css/parsing-object-position.html
+++ b/third_party/WebKit/LayoutTests/fast/css/parsing-object-position.html
@@ -36,7 +36,7 @@
             shouldBeEqualToString('testComputedStyle("object-position: top right;")', '100% 0%');
             shouldBeEqualToString('testComputedStyle("object-position: left 20px bottom 50%;")', '20px 50%');
             shouldBeEqualToString('testComputedStyle("object-position: right 50% bottom 25%;")', '50% 75%');
-            shouldBeEqualToString('testComputedStyle("object-position: bottom 20px right 12px;")', 'calc(-12px + 100%) calc(-20px + 100%)');
+            shouldBeEqualToString('testComputedStyle("object-position: bottom 20px right 12px;")', 'calc(100% + -12px) calc(100% + -20px)');
 
             shouldBeEqualToString('test("object-position: inherit;")', 'inherit');
             shouldBeEqualToString('test("object-position: initial;")', 'initial');
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Range/range-expand.html b/third_party/WebKit/LayoutTests/fast/dom/Range/range-expand.html
index 2eb62da..cbae6e7 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/Range/range-expand.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/Range/range-expand.html
@@ -85,14 +85,6 @@
     assert_equals(actual, 'multiple lines.');
   }, 'sentence11');
 
-  // Sentence end expansion should not cross block boundaries.
-  test(() => {
-    const id = 'begin';
-    const length = document.getElementById(id).firstChild.length;
-    const actual = expandRangeString(id, length, id, length, 'sentence', true);
-    assert_equals(actual, 'Each sentence begins with capital\nletter and ends with a punctuation.');
-  }, 'sentence12');
-
   // Expand word.
   // Same range start and end, both at the begin of word.
   test(() => {
@@ -226,7 +218,7 @@
 }
 </script>
 <body>
-<p id="begin">This is the begin of a block. A block is a collection of sentences. Each sentence begins with capital
+<p>This is the begin of a block. A block is a collection of sentences. Each sentence begins with capital
 letter and ends with a punctuation.
 </p>
 <pre id="multilineSentence">Now, a sentence
diff --git a/third_party/WebKit/LayoutTests/fast/shapes/parsing/parsing-shape-margin-expected.txt b/third_party/WebKit/LayoutTests/fast/shapes/parsing/parsing-shape-margin-expected.txt
index 485a902..664aac3 100644
--- a/third_party/WebKit/LayoutTests/fast/shapes/parsing/parsing-shape-margin-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/shapes/parsing/parsing-shape-margin-expected.txt
@@ -20,7 +20,7 @@
 PASS getComputedStyleValue("shape-margin", "-5em") is "0px"
 PASS getComputedStyleValue("shape-margin", "identifier") is "0px"
 PASS getComputedStyleValue("shape-margin", "'string'") is "0px"
-PASS getComputedStyleValue("shape-margin", "calc(25%*3 - 10in)") is "calc(-960px + 75%)"
+PASS getComputedStyleValue("shape-margin", "calc(25%*3 - 10in)") is "calc(75% + -960px)"
 PASS getChildComputedStyle("shape-margin", "0", "0") is "0px"
 PASS getChildComputedStyle("shape-margin", "0", "1px") is "1px"
 PASS getChildComputedStyle("shape-margin", "1px", "-1em") is "0px"
diff --git a/third_party/WebKit/LayoutTests/fast/shapes/parsing/parsing-shape-margin.html b/third_party/WebKit/LayoutTests/fast/shapes/parsing/parsing-shape-margin.html
index d461c99..659eda3 100644
--- a/third_party/WebKit/LayoutTests/fast/shapes/parsing/parsing-shape-margin.html
+++ b/third_party/WebKit/LayoutTests/fast/shapes/parsing/parsing-shape-margin.html
@@ -28,7 +28,7 @@
      ["shape-margin", "-5em", "0px"],
      ["shape-margin", "identifier", "0px"],
      ["shape-margin", "\'string\'", "0px"],
-     ["shape-margin", "calc(25%*3 - 10in)", "calc(-960px + 75%)"]]
+     ["shape-margin", "calc(25%*3 - 10in)", "calc(75% + -960px)"]]
 );
 
 applyToEachArglist(
diff --git a/third_party/WebKit/LayoutTests/fast/shapes/parsing/parsing-shape-outside-expected.txt b/third_party/WebKit/LayoutTests/fast/shapes/parsing/parsing-shape-outside-expected.txt
index 5a7b3937..4e6cfc83 100644
--- a/third_party/WebKit/LayoutTests/fast/shapes/parsing/parsing-shape-outside-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/shapes/parsing/parsing-shape-outside-expected.txt
@@ -67,9 +67,9 @@
 PASS getCSSText("shape-outside", "inset(10px round 0px / 10px)") is "inset(10px round 0px / 10px)"
 PASS getComputedStyleValue("shape-outside", "inset(10px round 0px / 10px)") is "inset(10px round 0px / 10px)"
 PASS getCSSText("shape-outside", "inset(calc(25%*3 - 10in) 0 0 0)") is "inset(calc(75% - 10in) 0px 0px)"
-PASS getComputedStyleValue("shape-outside", "inset(calc(25%*3 - 10in) 0 0 0)") is "inset(calc(-960px + 75%) 0px 0px)"
+FAIL getComputedStyleValue("shape-outside", "inset(calc(25%*3 - 10in) 0 0 0)") should be inset(calc(-960px + 75%) 0px 0px). Was inset(calc(75% + -960px) 0px 0px).
 PASS getCSSText("shape-outside", "inset(10px 10px 10px 10px round calc(25%*3 - 10in))") is "inset(10px round calc(75% - 10in))"
-PASS getComputedStyleValue("shape-outside", "inset(10px 10px 10px 10px round calc(25%*3 - 10in))") is "inset(10px round calc(-960px + 75%))"
+FAIL getComputedStyleValue("shape-outside", "inset(10px 10px 10px 10px round calc(25%*3 - 10in))") should be inset(10px round calc(-960px + 75%)). Was inset(10px round calc(75% + -960px)).
 PASS getCSSText("shape-outside", "circle()") is "circle(at 50% 50%)"
 PASS getComputedStyleValue("shape-outside", "circle()") is "circle(at 50% 50%)"
 PASS getCSSText("shape-outside", "circle(farthest-side)") is "circle(farthest-side at 50% 50%)"
diff --git a/third_party/WebKit/LayoutTests/transforms/translate-parsing.html b/third_party/WebKit/LayoutTests/transforms/translate-parsing.html
index be40ca0..fdd82133 100644
--- a/third_party/WebKit/LayoutTests/transforms/translate-parsing.html
+++ b/third_party/WebKit/LayoutTests/transforms/translate-parsing.html
@@ -19,8 +19,8 @@
 expect('42.5% -20.5% 5px').parsesAs('42.5% -20.5% 5px').isComputedTo('42.5% -20.5% 5px');
 
 expect('calc(100%) calc(20px) calc(-1px)').isComputedTo('100% 20px -1px');
-expect('calc(100% + 10px) calc(100% - 10px) calc(100px + 200px)').parsesAs('calc(100% + 10px) calc(100% - 10px) calc(300px)').isComputedTo('calc(10px + 100%) calc(-10px + 100%) 300px');
-expect('calc(100% * 0.5 + 2px) calc(100% - 10px / 2) calc(100px - 200px)').parsesAs('calc(50% + 2px) calc(100% - 5px) calc(-100px)').isComputedTo('calc(2px + 50%) calc(-5px + 100%) -100px');
+expect('calc(100% + 10px) calc(100% - 10px) calc(100px + 200px)').parsesAs('calc(100% + 10px) calc(100% - 10px) calc(300px)').isComputedTo('calc(100% + 10px) calc(100% + -10px) 300px');
+expect('calc(100% * 0.5 + 2px) calc(100% - 10px / 2) calc(100px - 200px)').parsesAs('calc(50% + 2px) calc(100% - 5px) calc(-100px)').isComputedTo('calc(50% + 2px) calc(100% + -5px) -100px');
 
 expect('2').isInvalid();
 expect('10deg 10px').isInvalid();
diff --git a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
index d371bdc4..3db6052 100644
--- a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
@@ -73,6 +73,7 @@
     property ariaValueNow
     property ariaValueText
     property assignedSlot
+    property attachInternals
     property attachShadow
     property attributeStyleMap
     property attributes
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 8cd019b6..c92195b2 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -2035,6 +2035,9 @@
     setter scrollLeft
     setter scrollTop
     setter slot
+interface ElementInternals
+    attribute @@toStringTag
+    method constructor
 interface EnterPictureInPictureEvent : Event
     attribute @@toStringTag
     getter pictureInPictureWindow
@@ -2656,6 +2659,7 @@
     getter tabIndex
     getter title
     getter translate
+    method attachInternals
     method blur
     method click
     method constructor
diff --git a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
index ead42a8..1042a3e 100644
--- a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
+++ b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
@@ -32,18 +32,28 @@
   return v8::Null(isolate);
 }
 
-bool IsCallbackFunctionRunnable(
+namespace {
+
+enum class IgnorePause { kDontIgnore, kIgnore };
+
+// 'beforeunload' event listeners are runnable even when execution contexts are
+// paused. Use |RespectPause::kPrioritizeOverPause| in such a case.
+bool IsCallbackFunctionRunnableInternal(
     const ScriptState* callback_relevant_script_state,
-    ScriptState* incumbent_script_state) {
+    const ScriptState* incumbent_script_state,
+    IgnorePause ignore_pause) {
   if (!callback_relevant_script_state->ContextIsValid())
     return false;
   const ExecutionContext* relevant_execution_context =
       ExecutionContext::From(callback_relevant_script_state);
   if (!relevant_execution_context ||
-      relevant_execution_context->IsContextPaused() ||
       relevant_execution_context->IsContextDestroyed()) {
     return false;
   }
+  if (relevant_execution_context->IsContextPaused()) {
+    if (ignore_pause == IgnorePause::kDontIgnore)
+      return false;
+  }
 
   // TODO(yukishiino): Callback function type value must make the incumbent
   // environment alive, i.e. the reference to v8::Context must be strong.
@@ -60,12 +70,34 @@
   // the callback.
   // TODO(crbug.com/608641): move IsMainWorld check into
   // ExecutionContext::CanExecuteScripts()
-  return incumbent_execution_context &&
-         !incumbent_execution_context->IsContextPaused() &&
-         !incumbent_execution_context->IsContextDestroyed() &&
-         (!incumbent_script_state->World().IsMainWorld() ||
-          incumbent_execution_context->CanExecuteScripts(
-              kAboutToExecuteScript));
+  if (!incumbent_execution_context ||
+      incumbent_execution_context->IsContextDestroyed()) {
+    return false;
+  }
+  if (incumbent_execution_context->IsContextPaused()) {
+    if (ignore_pause == IgnorePause::kDontIgnore)
+      return false;
+  }
+  return !incumbent_script_state->World().IsMainWorld() ||
+         incumbent_execution_context->CanExecuteScripts(kAboutToExecuteScript);
+}
+
+}  // namespace
+
+bool IsCallbackFunctionRunnable(
+    const ScriptState* callback_relevant_script_state,
+    const ScriptState* incumbent_script_state) {
+  return IsCallbackFunctionRunnableInternal(callback_relevant_script_state,
+                                            incumbent_script_state,
+                                            IgnorePause::kDontIgnore);
+}
+
+bool IsCallbackFunctionRunnableIgnoringPause(
+    const ScriptState* callback_relevant_script_state,
+    const ScriptState* incumbent_script_state) {
+  return IsCallbackFunctionRunnableInternal(callback_relevant_script_state,
+                                            incumbent_script_state,
+                                            IgnorePause::kIgnore);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
index 806710d2..43c33dd 100644
--- a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
+++ b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
@@ -36,7 +36,7 @@
 // Promise-returning DOM operations are required to always return a promise
 // and to never throw an exception.
 // See also http://heycam.github.io/webidl/#es-operations
-class CORE_EXPORT ExceptionToRejectPromiseScope {
+class CORE_EXPORT ExceptionToRejectPromiseScope final {
   STACK_ALLOCATED();
 
  public:
@@ -62,7 +62,11 @@
 
 CORE_EXPORT bool IsCallbackFunctionRunnable(
     const ScriptState* callback_relevant_script_state,
-    ScriptState* incumbent_script_state);
+    const ScriptState* incumbent_script_state);
+
+CORE_EXPORT bool IsCallbackFunctionRunnableIgnoringPause(
+    const ScriptState* callback_relevant_script_state,
+    const ScriptState* incumbent_script_state);
 
 using InstallTemplateFunction =
     void (*)(v8::Isolate* isolate,
diff --git a/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc b/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc
index 5bab0a1b..1f6b5cc 100644
--- a/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc
+++ b/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc
@@ -103,8 +103,19 @@
     arguments = {ScriptValue::From(script_state_of_listener, js_event)};
   }
 
+  const bool is_beforeunload_event =
+      event.IsBeforeUnloadEvent() &&
+      event.type() == event_type_names::kBeforeunload;
+  if (!event_handler_->IsRunnableOrThrowException(
+          is_beforeunload_event
+              ? V8EventHandlerNonNull::IgnorePause::kIgnore
+              : V8EventHandlerNonNull::IgnorePause::kDontIgnore)) {
+    return;
+  }
   ScriptValue result;
-  if (!event_handler_->Invoke(event.currentTarget(), arguments).To(&result) ||
+  if (!event_handler_
+           ->InvokeWithoutRunnabilityCheck(event.currentTarget(), arguments)
+           .To(&result) ||
       GetIsolate()->IsExecutionTerminating())
     return;
   v8::Local<v8::Value> v8_return_value = result.V8Value();
@@ -124,7 +135,7 @@
   String result_for_beforeunload;
   if (IsOnBeforeUnloadEventHandler()) {
     // TODO(yukiy): use |NativeValueTraits|.
-    V8StringResource<> native_result(v8_return_value);
+    V8StringResource<kTreatNullAsNullString> native_result(v8_return_value);
 
     // |native_result.Prepare()| throws exception if it fails to convert
     // |native_result| to String.
@@ -148,8 +159,7 @@
   //             then return value will never be false, since in such cases
   //             return value will have been coerced into either null or a
   //             DOMString.
-  if (event.IsBeforeUnloadEvent() &&
-      event.type() == event_type_names::kBeforeunload) {
+  if (is_beforeunload_event) {
     if (result_for_beforeunload) {
       event.preventDefault();
       BeforeUnloadEvent* before_unload_event = ToBeforeUnloadEvent(&event);
diff --git a/third_party/blink/renderer/bindings/core/v8/js_event_listener.cc b/third_party/blink/renderer/bindings/core/v8/js_event_listener.cc
index 0fe8532..558a038 100644
--- a/third_party/blink/renderer/bindings/core/v8/js_event_listener.cc
+++ b/third_party/blink/renderer/bindings/core/v8/js_event_listener.cc
@@ -47,8 +47,16 @@
                                      v8::Local<v8::Value> js_event) {
   // Step 10: Call a listener with event's currentTarget as receiver and event
   // and handle errors if thrown.
-  v8::Maybe<void> maybe_result =
-      event_listener_->handleEvent(event.currentTarget(), &event);
+  const bool is_beforeunload_event =
+      event.IsBeforeUnloadEvent() &&
+      event.type() == event_type_names::kBeforeunload;
+  if (!event_listener_->IsRunnableOrThrowException(
+          is_beforeunload_event ? V8EventListener::IgnorePause::kIgnore
+                                : V8EventListener::IgnorePause::kDontIgnore)) {
+    return;
+  }
+  v8::Maybe<void> maybe_result = event_listener_->InvokeWithoutRunnabilityCheck(
+      event.currentTarget(), &event);
   ALLOW_UNUSED_LOCAL(maybe_result);
 }
 
diff --git a/third_party/blink/renderer/bindings/templates/callback_function.cc.tmpl b/third_party/blink/renderer/bindings/templates/callback_function.cc.tmpl
index f846c67b..9331774 100644
--- a/third_party/blink/renderer/bindings/templates/callback_function.cc.tmpl
+++ b/third_party/blink/renderer/bindings/templates/callback_function.cc.tmpl
@@ -19,7 +19,7 @@
 {{callback_invoke(
     'callback function', 'invoke',
     return_cpp_type, native_value_traits_tag, arguments,
-    is_treat_non_object_as_null,
+    is_treat_non_object_as_null, False,
     callback_function_name, 'invoke')}}
 }
 
@@ -28,7 +28,7 @@
 {{callback_invoke(
     'callback function', 'construct',
     return_cpp_type, native_value_traits_tag, arguments,
-    is_treat_non_object_as_null,
+    is_treat_non_object_as_null, False,
     callback_function_name, 'construct')}}
 }
 {% endif %}
@@ -49,6 +49,42 @@
 }
 {% endif %}
 
+{% if callback_function_name == 'EventHandlerNonNull' %}
+bool {{cpp_class}}::IsRunnableOrThrowException(IgnorePause ignore_pause) {
+  bool is_runnable =
+      ignore_pause == IgnorePause::kIgnore ?
+      IsCallbackFunctionRunnableIgnoringPause(
+          CallbackRelevantScriptState(), IncumbentScriptState()) :
+      IsCallbackFunctionRunnable(
+          CallbackRelevantScriptState(), IncumbentScriptState());
+  if (is_runnable)
+    return true;
+
+  // Wrapper-tracing for the callback function makes the function object and
+  // its creation context alive. Thus it's safe to use the creation context
+  // of the callback function here.
+  v8::HandleScope handle_scope(GetIsolate());
+  v8::Local<v8::Object> callback_object = CallbackObject();
+  CHECK(!callback_object.IsEmpty());
+  v8::Context::Scope context_scope(callback_object->CreationContext());
+  V8ThrowException::ThrowError(
+      GetIsolate(),
+      ExceptionMessages::FailedToExecute(
+          "invoke",
+          "{{callback_function_name}}",
+          "The provided callback is no longer runnable."));
+  return false;
+}
+
+v8::Maybe<{{return_cpp_type}}> {{cpp_class}}::InvokeWithoutRunnabilityCheck({{argument_declarations | join(', ')}}) {
+{{callback_invoke(
+    'callback function', 'invoke',
+    return_cpp_type, native_value_traits_tag, arguments,
+    is_treat_non_object_as_null, True,
+    callback_function_name, 'invoke')}}
+}
+{% endif %}
+
 v8::Maybe<{{return_cpp_type}}> V8PersistentCallbackFunction<{{cpp_class}}>::Invoke({{argument_declarations | join(', ')}}) {
   return Proxy()->Invoke(
       {{
diff --git a/third_party/blink/renderer/bindings/templates/callback_function.h.tmpl b/third_party/blink/renderer/bindings/templates/callback_function.h.tmpl
index b98ed18b..bb739787b 100644
--- a/third_party/blink/renderer/bindings/templates/callback_function.h.tmpl
+++ b/third_party/blink/renderer/bindings/templates/callback_function.h.tmpl
@@ -51,6 +51,20 @@
   // error handler such as DevTools' console.
   void InvokeAndReportException({{argument_declarations | join(', ')}});
 {% endif %}
+
+{% if callback_function_name == 'EventHandlerNonNull' %}
+  // Returns true if the callback is runnable, otherwise returns false and
+  // throws an exception. 'beforeunload' event need to have priority over pause
+  // of execution contexts.
+  enum class IgnorePause { kDontIgnore, kIgnore };
+  bool IsRunnableOrThrowException(IgnorePause);
+
+  // Performs "invoke" without checking the runnability check, which must be
+  // done prior to this call by |IsRunnableOrThrowException|.
+  // https://heycam.github.io/webidl/#es-invoking-callback-functions
+  // This function may throw unlike InvokeAndReportException.
+  v8::Maybe<{{return_cpp_type}}> InvokeWithoutRunnabilityCheck({{argument_declarations | join(', ')}}) WARN_UNUSED_RESULT;
+{% endif %}
 };
 
 template <>
diff --git a/third_party/blink/renderer/bindings/templates/callback_interface.cc.tmpl b/third_party/blink/renderer/bindings/templates/callback_interface.cc.tmpl
index ef4f63f..67f6d87 100644
--- a/third_party/blink/renderer/bindings/templates/callback_interface.cc.tmpl
+++ b/third_party/blink/renderer/bindings/templates/callback_interface.cc.tmpl
@@ -88,7 +88,7 @@
 {{callback_invoke(
     'callback interface', None,
     method.cpp_type, method.native_value_traits_tag, method.arguments,
-    False,
+    False, False,
     interface_name, method.name)}}
 }
 
@@ -110,6 +110,42 @@
 }
 {% endif %}
 
+{% if interface_name == 'EventListener' %}
+bool {{v8_class}}::IsRunnableOrThrowException(IgnorePause ignore_pause) {
+  bool is_runnable =
+      ignore_pause == IgnorePause::kIgnore ?
+      IsCallbackFunctionRunnableIgnoringPause(
+          CallbackRelevantScriptState(), IncumbentScriptState()) :
+      IsCallbackFunctionRunnable(
+          CallbackRelevantScriptState(), IncumbentScriptState());
+  if (is_runnable)
+    return true;
+
+  // Wrapper-tracing for the callback function makes the function object and
+  // its creation context alive. Thus it's safe to use the creation context
+  // of the callback function here.
+  v8::HandleScope handle_scope(GetIsolate());
+  v8::Local<v8::Object> callback_object = CallbackObject();
+  CHECK(!callback_object.IsEmpty());
+  v8::Context::Scope context_scope(callback_object->CreationContext());
+  V8ThrowException::ThrowError(
+      GetIsolate(),
+      ExceptionMessages::FailedToExecute(
+          "{{methods[0].name}}",
+          "{{interface_name}}",
+          "The provided callback is no longer runnable."));
+  return false;
+}
+
+v8::Maybe<{{methods[0].cpp_type}}> {{v8_class}}::InvokeWithoutRunnabilityCheck({{methods[0].argument_declarations | join(', ')}}) {
+{{callback_invoke(
+    'callback interface', None,
+    methods[0].cpp_type, methods[0].native_value_traits_tag, methods[0].arguments,
+    False, True,
+    interface_name, methods[0].name)}}
+}
+{% endif %}
+
 {% for method in methods %}
 v8::Maybe<{{method.cpp_type}}> V8PersistentCallbackInterface<{{v8_class}}>::{{method.name}}({{method.argument_declarations | join(', ')}}) {
   return Proxy()->{{method.name}}(
diff --git a/third_party/blink/renderer/bindings/templates/callback_interface.h.tmpl b/third_party/blink/renderer/bindings/templates/callback_interface.h.tmpl
index 45fc0aea..fd99135 100644
--- a/third_party/blink/renderer/bindings/templates/callback_interface.h.tmpl
+++ b/third_party/blink/renderer/bindings/templates/callback_interface.h.tmpl
@@ -57,6 +57,21 @@
   // if any, to the global error handler such as DevTools' console.
   void InvokeAndReportException({{methods[0].argument_declarations | join(', ')}});
 {% endif %}
+
+{% if interface_name == 'EventListener' %}
+  // Returns true if the callback is runnable, otherwise returns false and
+  // throws an exception. 'beforeunload' event need to have priority over pause
+  // of execution contexts.
+  enum class IgnorePause { kDontIgnore, kIgnore };
+  bool IsRunnableOrThrowException(IgnorePause);
+
+  // Performs "call a user object's operation" for '{{methods[0].name}}' without
+  // checking the runnability check, which must be done prior to this call by
+  // |IsRunnableOrThrowException|.
+  // https://heycam.github.io/webidl/#call-a-user-objects-operation
+  // This function may throw unlike InvokeAndReportException.
+  v8::Maybe<{{methods[0].cpp_type}}> InvokeWithoutRunnabilityCheck({{methods[0].argument_declarations | join(', ')}}) WARN_UNUSED_RESULT;
+{% endif %}
 };
 
 template <>
diff --git a/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl b/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl
index 97bf37f..231d687 100644
--- a/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl
+++ b/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl
@@ -12,25 +12,23 @@
       return_native_value_traits_tag = tag of NativeValueTraits for return type
       arguments = dict of arguments\' info
       is_treat_non_object_as_null = True if [TreatNonObjectAsNull]
+      bypass_runnability_check = Skip IsCallbackFunctionRunnable check if True
       interface_name = interface name used for exception
       operation_name = interface name used for exception and property lookup
 #}
 {% macro callback_invoke(
     interface_or_function, invoke_or_construct,
     return_cpp_type, return_native_value_traits_tag, arguments,
-    is_treat_non_object_as_null,
+    is_treat_non_object_as_null, bypass_runnability_check,
     interface_name, operation_name) %}
+  {% if not bypass_runnability_check %}
   if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState(),
                                   IncumbentScriptState())) {
     // Wrapper-tracing for the callback function makes the function object and
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    {% if interface_or_function == 'callback function' %}
-    v8::Local<v8::Object> callback_object = CallbackFunction();
-    {% else %}
     v8::Local<v8::Object> callback_object = CallbackObject();
-    {% endif %}
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
@@ -41,6 +39,7 @@
             "The provided callback is no longer runnable."));
     return v8::Nothing<{{return_cpp_type}}>();
   }
+  {% endif %}
 
   // step: Prepare to run script with relevant settings.
   ScriptState::Scope callback_relevant_context_scope(
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc
index 81378ef..c3e866dc 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc
@@ -34,7 +34,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
@@ -114,7 +114,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.cc
index c44f741..a50c7e13 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.cc
@@ -34,7 +34,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
@@ -115,7 +115,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_long_callback_function.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_long_callback_function.cc
index f42b1a0..b277f5582 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_long_callback_function.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_long_callback_function.cc
@@ -34,7 +34,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc
index ebe09c58..57d6334 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc
@@ -34,7 +34,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_boolean_function.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_boolean_function.cc
index 3f745af0..f5d5dee 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_boolean_function.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_boolean_function.cc
@@ -33,7 +33,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_void_function.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_void_function.cc
index ae23a87..110a615f 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_void_function.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_void_function.cc
@@ -33,7 +33,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function.cc
index 8e9b8564..135cbec 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function.cc
@@ -33,7 +33,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc
index c0cb04e77..b47f3dc3 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc
@@ -34,7 +34,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc
index eae3aba1..1748157 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc
@@ -34,7 +34,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc
index e13d389..f8f4e486 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc
@@ -34,7 +34,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc
index 3e25936..ffb2273 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc
@@ -35,7 +35,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_typedef.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_typedef.cc
index 8d05ea4..cc01356 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_typedef.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_typedef.cc
@@ -34,7 +34,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
diff --git a/third_party/blink/renderer/bindings/tests/results/modules/v8_void_callback_function_modules.cc b/third_party/blink/renderer/bindings/tests/results/modules/v8_void_callback_function_modules.cc
index f0e35e9..8cd929d 100644
--- a/third_party/blink/renderer/bindings/tests/results/modules/v8_void_callback_function_modules.cc
+++ b/third_party/blink/renderer/bindings/tests/results/modules/v8_void_callback_function_modules.cc
@@ -33,7 +33,7 @@
     // its creation context alive. Thus it's safe to use the creation context
     // of the callback function here.
     v8::HandleScope handle_scope(GetIsolate());
-    v8::Local<v8::Object> callback_object = CallbackFunction();
+    v8::Local<v8::Object> callback_object = CallbackObject();
     CHECK(!callback_object.IsEmpty());
     v8::Context::Scope context_scope(callback_object->CreationContext());
     V8ThrowException::ThrowError(
diff --git a/third_party/blink/renderer/core/core_idl_files.gni b/third_party/blink/renderer/core/core_idl_files.gni
index 27d03a5..133c44a 100644
--- a/third_party/blink/renderer/core/core_idl_files.gni
+++ b/third_party/blink/renderer/core/core_idl_files.gni
@@ -266,6 +266,7 @@
                     "html/canvas/image_data.idl",
                     "html/canvas/text_metrics.idl",
                     "html/custom/custom_element_registry.idl",
+                    "html/custom/element_internals.idl",
                     "html/forms/form_data.idl",
                     "html/forms/form_data_event.idl",
                     "html/forms/html_button_element.idl",
diff --git a/third_party/blink/renderer/core/css/css_calculation_value.cc b/third_party/blink/renderer/core/css/css_calculation_value.cc
index e785bd0..6145bbf3 100644
--- a/third_party/blink/renderer/core/css/css_calculation_value.cc
+++ b/third_party/blink/renderer/core/css/css_calculation_value.cc
@@ -837,13 +837,13 @@
 CSSCalcExpressionNode* CSSCalcValue::CreateExpressionNode(double pixels,
                                                           double percent) {
   return CreateExpressionNode(
-      CreateExpressionNode(CSSPrimitiveValue::Create(
-                               pixels, CSSPrimitiveValue::UnitType::kPixels),
-                           pixels == trunc(pixels)),
       CreateExpressionNode(
           CSSPrimitiveValue::Create(percent,
                                     CSSPrimitiveValue::UnitType::kPercentage),
           percent == trunc(percent)),
+      CreateExpressionNode(CSSPrimitiveValue::Create(
+                               pixels, CSSPrimitiveValue::UnitType::kPixels),
+                           pixels == trunc(pixels)),
       kCalcAdd);
 }
 
diff --git a/third_party/blink/renderer/core/dom/BUILD.gn b/third_party/blink/renderer/core/dom/BUILD.gn
index a2dbb332..b9b40b4a 100644
--- a/third_party/blink/renderer/core/dom/BUILD.gn
+++ b/third_party/blink/renderer/core/dom/BUILD.gn
@@ -139,6 +139,8 @@
     "events/window_event_context.h",
     "first_letter_pseudo_element.cc",
     "first_letter_pseudo_element.h",
+    "flat_tree_node_data.cc",
+    "flat_tree_node_data.h",
     "flat_tree_traversal.cc",
     "flat_tree_traversal.h",
     "frame_request_callback_collection.cc",
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 29bc436..17cce6b 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2666,6 +2666,14 @@
   return g_null_atom;
 }
 
+void Element::SetDidAttachInternals() {
+  EnsureElementRareData().SetDidAttachInternals();
+}
+
+bool Element::DidAttachInternals() const {
+  return HasRareData() && GetElementRareData()->DidAttachInternals();
+}
+
 ShadowRoot* Element::createShadowRoot(ExceptionState& exception_state) {
   if (ShadowRoot* root = GetShadowRoot()) {
     if (root->IsUserAgent()) {
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index c7bd09a0..28550728 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -808,6 +808,8 @@
   // https://dom.spec.whatwg.org/#concept-element-is-value
   void SetIsValue(const AtomicString&);
   const AtomicString& IsValue() const;
+  void SetDidAttachInternals();
+  bool DidAttachInternals() const;
 
   bool ContainsFullScreenElement() const {
     return HasElementFlag(ElementFlags::kContainsFullScreenElement);
diff --git a/third_party/blink/renderer/core/dom/element_rare_data.cc b/third_party/blink/renderer/core/dom/element_rare_data.cc
index 162506f..106d136 100644
--- a/third_party/blink/renderer/core/dom/element_rare_data.cc
+++ b/third_party/blink/renderer/core/dom/element_rare_data.cc
@@ -42,6 +42,7 @@
   IntSize scroll_offset;
   void* pointers_or_strings[5];
   Member<void*> members[15];
+  bool flags[1];
 };
 
 ElementRareData::ElementRareData(NodeRenderingData* node_layout_data)
diff --git a/third_party/blink/renderer/core/dom/element_rare_data.h b/third_party/blink/renderer/core/dom/element_rare_data.h
index 018d4e8..8357f1a 100644
--- a/third_party/blink/renderer/core/dom/element_rare_data.h
+++ b/third_party/blink/renderer/core/dom/element_rare_data.h
@@ -155,6 +155,8 @@
   }
   void SetIsValue(const AtomicString& is_value) { is_value_ = is_value; }
   const AtomicString& IsValue() const { return is_value_; }
+  void SetDidAttachInternals() { did_attach_internals_ = true; }
+  bool DidAttachInternals() const { return did_attach_internals_; }
 
   AccessibleNode* GetAccessibleNode() const { return accessible_node_.Get(); }
   AccessibleNode* EnsureAccessibleNode(Element* owner_element) {
@@ -235,6 +237,7 @@
   TraceWrapperMember<AccessibleNode> accessible_node_;
 
   WeakMember<DisplayLockContext> display_lock_context_;
+  bool did_attach_internals_ = false;
 
   explicit ElementRareData(NodeRenderingData*);
 };
diff --git a/third_party/blink/renderer/core/dom/flat_tree_node_data.cc b/third_party/blink/renderer/core/dom/flat_tree_node_data.cc
new file mode 100644
index 0000000..163ec43
--- /dev/null
+++ b/third_party/blink/renderer/core/dom/flat_tree_node_data.cc
@@ -0,0 +1,17 @@
+// 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 "third_party/blink/renderer/core/dom/flat_tree_node_data.h"
+
+#include "third_party/blink/renderer/core/html/html_slot_element.h"
+
+namespace blink {
+
+void FlatTreeNodeData::Trace(Visitor* visitor) {
+  visitor->Trace(assigned_slot_);
+  visitor->Trace(previous_in_assigned_nodes_);
+  visitor->Trace(next_in_assigned_nodes_);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/flat_tree_node_data.h b/third_party/blink/renderer/core/dom/flat_tree_node_data.h
new file mode 100644
index 0000000..aa0f0caf
--- /dev/null
+++ b/third_party/blink/renderer/core/dom/flat_tree_node_data.h
@@ -0,0 +1,45 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_CORE_DOM_FLAT_TREE_NODE_DATA_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_FLAT_TREE_NODE_DATA_H_
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+
+namespace blink {
+
+class Node;
+class HTMLSlotElement;
+
+class FlatTreeNodeData final : public GarbageCollected<FlatTreeNodeData> {
+ public:
+  FlatTreeNodeData() {}
+  void Trace(Visitor*);
+
+ private:
+  void SetAssignedSlot(HTMLSlotElement* assigned_slot) {
+    assigned_slot_ = assigned_slot;
+  }
+
+  void SetPreviousInAssignedNodes(Node* previous) {
+    previous_in_assigned_nodes_ = previous;
+  }
+  void SetNextInAssignedNodes(Node* next) { next_in_assigned_nodes_ = next; }
+
+  HTMLSlotElement* AssignedSlot() { return assigned_slot_; }
+  Node* PreviousInAssignedNodes() { return previous_in_assigned_nodes_; }
+  Node* NextInAssignedNodes() { return next_in_assigned_nodes_; }
+
+  friend class HTMLSlotElement;
+
+  WeakMember<HTMLSlotElement> assigned_slot_;
+  WeakMember<Node> previous_in_assigned_nodes_;
+  WeakMember<Node> next_in_assigned_nodes_;
+  DISALLOW_COPY_AND_ASSIGN(FlatTreeNodeData);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_DOM_FLAT_TREE_NODE_DATA_H_
diff --git a/third_party/blink/renderer/core/dom/flat_tree_traversal.cc b/third_party/blink/renderer/core/dom/flat_tree_traversal.cc
index f98a8b5..dd75d326 100644
--- a/third_party/blink/renderer/core/dom/flat_tree_traversal.cc
+++ b/third_party/blink/renderer/core/dom/flat_tree_traversal.cc
@@ -114,6 +114,8 @@
 Node* FlatTreeTraversal::TraverseSiblingsForV1HostChild(
     const Node& node,
     TraversalDirection direction) {
+  // TODO(crbug.com/906494): Use flat_tree_node_data::assigned_slot to avoid
+  // hashmap lookup
   HTMLSlotElement* slot = node.AssignedSlot();
   if (!slot)
     return nullptr;
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc
index b83901a..ed0465d 100644
--- a/third_party/blink/renderer/core/dom/node.cc
+++ b/third_party/blink/renderer/core/dom/node.cc
@@ -1250,6 +1250,16 @@
   RareData()->ClearNodeLists();
 }
 
+FlatTreeNodeData& Node::EnsureFlatTreeNodeData() {
+  return EnsureRareData().EnsureFlatTreeNodeData();
+}
+
+FlatTreeNodeData& Node::GetFlatTreeNodeData() const {
+  DCHECK(HasRareData());
+  DCHECK(RareData()->GetFlatTreeNodeData());
+  return *RareData()->GetFlatTreeNodeData();
+}
+
 bool Node::IsDescendantOf(const Node* other) const {
   // Return true if other is an ancestor of this, otherwise false
   if (!other || !other->hasChildren() || isConnected() != other->isConnected())
diff --git a/third_party/blink/renderer/core/dom/node.h b/third_party/blink/renderer/core/dom/node.h
index d8be414..acfe760 100644
--- a/third_party/blink/renderer/core/dom/node.h
+++ b/third_party/blink/renderer/core/dom/node.h
@@ -51,6 +51,7 @@
 class Event;
 class EventDispatchHandlingState;
 class ExceptionState;
+class FlatTreeNodeData;
 class GetRootNodeOptions;
 class HTMLQualifiedName;
 class HTMLSlotElement;
@@ -776,6 +777,10 @@
   NodeListsNodeData* NodeLists();
   void ClearNodeLists();
 
+  // EnsureFlatTreeNodeData() must be called beforehand
+  FlatTreeNodeData& GetFlatTreeNodeData() const;
+  FlatTreeNodeData& EnsureFlatTreeNodeData();
+
   virtual bool WillRespondToMouseMoveEvents();
   virtual bool WillRespondToMouseClickEvents();
   virtual bool WillRespondToTouchEvents();
diff --git a/third_party/blink/renderer/core/dom/node_rare_data.cc b/third_party/blink/renderer/core/dom/node_rare_data.cc
index f340e29..c50f45db9 100644
--- a/third_party/blink/renderer/core/dom/node_rare_data.cc
+++ b/third_party/blink/renderer/core/dom/node_rare_data.cc
@@ -33,6 +33,7 @@
 #include "third_party/blink/renderer/core/dom/container_node.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/element_rare_data.h"
+#include "third_party/blink/renderer/core/dom/flat_tree_node_data.h"
 #include "third_party/blink/renderer/core/dom/mutation_observer_registration.h"
 #include "third_party/blink/renderer/core/dom/node_lists_node_data.h"
 #include "third_party/blink/renderer/core/page/page.h"
@@ -43,7 +44,7 @@
 
 struct SameSizeAsNodeRareData {
   void* pointer_;
-  Member<void*> willbe_member_[2];
+  Member<void*> willbe_member_[3];
   unsigned bitfields_;
 };
 
@@ -83,6 +84,7 @@
 
 void NodeRareData::TraceAfterDispatch(blink::Visitor* visitor) {
   visitor->Trace(mutation_observer_data_);
+  visitor->Trace(flat_tree_node_data_);
   // Do not keep empty NodeListsNodeData objects around.
   if (node_lists_ && node_lists_->IsEmpty())
     node_lists_.Clear();
@@ -114,6 +116,12 @@
   return *node_lists_;
 }
 
+FlatTreeNodeData& NodeRareData::EnsureFlatTreeNodeData() {
+  if (!flat_tree_node_data_)
+    flat_tree_node_data_ = MakeGarbageCollected<FlatTreeNodeData>();
+  return *flat_tree_node_data_;
+}
+
 // Ensure the 10 bits reserved for the connected_frame_count_ cannot overflow.
 static_assert(Page::kMaxNumberOfFrames <
                   (1 << NodeRareData::kConnectedFrameCountBits),
diff --git a/third_party/blink/renderer/core/dom/node_rare_data.h b/third_party/blink/renderer/core/dom/node_rare_data.h
index 394632d8..80e8c9e 100644
--- a/third_party/blink/renderer/core/dom/node_rare_data.h
+++ b/third_party/blink/renderer/core/dom/node_rare_data.h
@@ -32,6 +32,7 @@
 class ComputedStyle;
 enum class DynamicRestyleFlags;
 enum class ElementFlags;
+class FlatTreeNodeData;
 class LayoutObject;
 class MutationObserverRegistration;
 class NodeListsNodeData;
@@ -134,6 +135,9 @@
     return *node_lists_;
   }
 
+  FlatTreeNodeData* GetFlatTreeNodeData() const { return flat_tree_node_data_; }
+  FlatTreeNodeData& EnsureFlatTreeNodeData();
+
   NodeMutationObserverData* MutationObserverData() {
     return mutation_observer_data_.Get();
   }
@@ -197,6 +201,7 @@
 
   TraceWrapperMember<NodeListsNodeData> node_lists_;
   TraceWrapperMember<NodeMutationObserverData> mutation_observer_data_;
+  Member<FlatTreeNodeData> flat_tree_node_data_;
 
   unsigned connected_frame_count_ : kConnectedFrameCountBits;
   unsigned element_flags_ : kNumberOfElementFlags;
diff --git a/third_party/blink/renderer/core/dom/slot_assignment.cc b/third_party/blink/renderer/core/dom/slot_assignment.cc
index fd2164f..fc6aa2d 100644
--- a/third_party/blink/renderer/core/dom/slot_assignment.cc
+++ b/third_party/blink/renderer/core/dom/slot_assignment.cc
@@ -229,7 +229,7 @@
   needs_assignment_recalc_ = false;
 
   for (Member<HTMLSlotElement> slot : Slots())
-    slot->ClearAssignedNodes();
+    slot->WillRecalcAssignedNodes();
 
   const bool is_user_agent = owner_->IsUserAgent();
 
@@ -266,10 +266,15 @@
       }
     }
 
-    if (slot)
+    if (slot) {
       slot->AppendAssignedNode(child);
-    else
+    } else {
+      // TODO(crbug.com/906494) Clear child's flat_tree_node_data here, which
+      // should be useful for shortcut in flat tree traversal later; we can skip
+      // hashmap lookup (node->slot) there if we know the node doesn't have
+      // an assigned slot.
       child.LazyReattachIfAttached();
+    }
   }
 
   if (owner_->isConnected()) {
@@ -279,7 +284,7 @@
   }
 
   for (auto& slot : Slots())
-    slot->RecalcFlatTreeChildren();
+    slot->DidRecalcAssignedNodes();
 }
 
 const HeapVector<Member<HTMLSlotElement>>& SlotAssignment::Slots() {
diff --git a/third_party/blink/renderer/core/editing/visible_units_sentence.cc b/third_party/blink/renderer/core/editing/visible_units_sentence.cc
index 6e05a61..5f3d78d 100644
--- a/third_party/blink/renderer/core/editing/visible_units_sentence.cc
+++ b/third_party/blink/renderer/core/editing/visible_units_sentence.cc
@@ -103,13 +103,8 @@
       // between sentences.
       const unsigned offset = FindNonSpaceCharacter(text, passed_offset);
       const int result = iterator->following(offset);
-      if (result == kTextBreakDone) {
-        if (text.length()) {
-          // Block boundaries are also sentence boundaries.
-          return Position::After(text.length());
-        }
+      if (result == kTextBreakDone)
         return Position();
-      }
       return result == 0 ? Position::Before(0) : Position::After(result - 1);
     }
 
diff --git a/third_party/blink/renderer/core/html/BUILD.gn b/third_party/blink/renderer/core/html/BUILD.gn
index f683b5c..24cd814 100644
--- a/third_party/blink/renderer/core/html/BUILD.gn
+++ b/third_party/blink/renderer/core/html/BUILD.gn
@@ -68,6 +68,8 @@
     "custom/custom_element_upgrade_reaction.h",
     "custom/custom_element_upgrade_sorter.cc",
     "custom/custom_element_upgrade_sorter.h",
+    "custom/element_internals.cc",
+    "custom/element_internals.h",
     "custom/v0_custom_element.cc",
     "custom/v0_custom_element.h",
     "custom/v0_custom_element_async_import_microtask_queue.cc",
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_definition.h b/third_party/blink/renderer/core/html/custom/custom_element_definition.h
index d55ab46b..8a0ef82 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_definition.h
+++ b/third_party/blink/renderer/core/html/custom/custom_element_definition.h
@@ -103,6 +103,7 @@
   bool HasDefaultStyleSheets() const {
     return !default_style_sheets_.IsEmpty();
   }
+  bool DisableInternals() const { return disable_internals_; }
 
   class CORE_EXPORT ConstructionStackScope final {
     STACK_ALLOCATED();
diff --git a/third_party/blink/renderer/core/html/custom/element_internals.cc b/third_party/blink/renderer/core/html/custom/element_internals.cc
new file mode 100644
index 0000000..d5805d07
--- /dev/null
+++ b/third_party/blink/renderer/core/html/custom/element_internals.cc
@@ -0,0 +1,18 @@
+// 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 "third_party/blink/renderer/core/html/custom/element_internals.h"
+
+#include "third_party/blink/renderer/core/html/html_element.h"
+
+namespace blink {
+
+ElementInternals::ElementInternals(HTMLElement& target) : target_(target) {}
+
+void ElementInternals::Trace(Visitor* visitor) {
+  visitor->Trace(target_);
+  ScriptWrappable::Trace(visitor);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/html/custom/element_internals.h b/third_party/blink/renderer/core/html/custom/element_internals.h
new file mode 100644
index 0000000..b3ab9537
--- /dev/null
+++ b/third_party/blink/renderer/core/html/custom/element_internals.h
@@ -0,0 +1,28 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_ELEMENT_INTERNALS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_ELEMENT_INTERNALS_H_
+
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace blink {
+
+class HTMLElement;
+
+class ElementInternals : public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  ElementInternals(HTMLElement& target);
+  void Trace(Visitor* visitor) override;
+
+ private:
+  Member<HTMLElement> target_;
+
+  DISALLOW_COPY_AND_ASSIGN(ElementInternals);
+};
+
+}  // namespace blink
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_ELEMENT_INTERNALS_H_
diff --git a/third_party/blink/renderer/core/html/custom/element_internals.idl b/third_party/blink/renderer/core/html/custom/element_internals.idl
new file mode 100644
index 0000000..539d9b02
--- /dev/null
+++ b/third_party/blink/renderer/core/html/custom/element_internals.idl
@@ -0,0 +1,14 @@
+// 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.
+
+// https://docs.google.com/document/d/1JO8puctCSpW-ZYGU8lF-h4FWRIDQNDVexzHoOQ2iQmY/edit?pli=1#heading=h.pjt9nhs3gu3k
+
+[
+  Exposed=Window,
+  RuntimeEnabled=ElementInternals
+]
+interface ElementInternals {
+  // TODO(tkent): Add operations.
+};
+
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc
index c77dd27..d1e8a89b 100644
--- a/third_party/blink/renderer/core/html/html_element.cc
+++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -36,6 +36,7 @@
 #include "third_party/blink/renderer/core/css/style_change_reason.h"
 #include "third_party/blink/renderer/core/css_value_keywords.h"
 #include "third_party/blink/renderer/core/dom/document_fragment.h"
+#include "third_party/blink/renderer/core/dom/element_rare_data.h"
 #include "third_party/blink/renderer/core/dom/element_traversal.h"
 #include "third_party/blink/renderer/core/dom/events/event_listener.h"
 #include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
@@ -51,6 +52,9 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_registry.h"
+#include "third_party/blink/renderer/core/html/custom/element_internals.h"
 #include "third_party/blink/renderer/core/html/forms/html_form_element.h"
 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
 #include "third_party/blink/renderer/core/html/html_br_element.h"
@@ -1407,6 +1411,32 @@
   Element::ParseAttribute(params);
 }
 
+ElementInternals* HTMLElement::attachInternals(
+    ExceptionState& exception_state) {
+  auto* definition =
+      CustomElement::Registry(*this)->DefinitionForName(localName());
+  if (!definition) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kInvalidStateError,
+        "Unable to attach ElementInternals to non-custom elements.");
+    return nullptr;
+  }
+  if (definition->DisableInternals()) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kInvalidStateError,
+        "ElementInternals is disabled by disabledFeature static field.");
+    return nullptr;
+  }
+  if (DidAttachInternals()) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kInvalidStateError,
+        "ElementInternals for the specified element was already attached.");
+    return nullptr;
+  }
+  SetDidAttachInternals();
+  return MakeGarbageCollected<ElementInternals>(*this);
+}
+
 }  // namespace blink
 
 #ifndef NDEBUG
diff --git a/third_party/blink/renderer/core/html/html_element.h b/third_party/blink/renderer/core/html/html_element.h
index 564baf3..d28661d 100644
--- a/third_party/blink/renderer/core/html/html_element.h
+++ b/third_party/blink/renderer/core/html/html_element.h
@@ -32,6 +32,7 @@
 struct AttributeTriggers;
 class Color;
 class DocumentFragment;
+class ElementInternals;
 class ExceptionState;
 class FormAssociated;
 class HTMLFormElement;
@@ -129,6 +130,7 @@
 
   Element* unclosedOffsetParent();
 
+  ElementInternals* attachInternals(ExceptionState& exception_state);
   virtual FormAssociated* ToFormAssociatedOrNull() { return nullptr; };
 
  protected:
diff --git a/third_party/blink/renderer/core/html/html_element.idl b/third_party/blink/renderer/core/html/html_element.idl
index 771d67c1..d148491 100644
--- a/third_party/blink/renderer/core/html/html_element.idl
+++ b/third_party/blink/renderer/core/html/html_element.idl
@@ -58,6 +58,10 @@
     // https://drafts.csswg.org/cssom/#the-elementcssinlinestyle-interface
     [Affects=Nothing, SameObject, PerWorldBindings, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
 
+    // Form-associated custom elements
+    // https://docs.google.com/document/d/1JO8puctCSpW-ZYGU8lF-h4FWRIDQNDVexzHoOQ2iQmY/edit?pli=1#heading=h.pjt9nhs3gu3k
+    [RuntimeEnabled=ElementInternals, RaisesException] ElementInternals attachInternals();
+
     // Non-standard APIs
     [Affects=Nothing, CEReactions, CustomElementCallbacks, RaisesException=Setter, MeasureAs=HTMLElementInnerText] attribute ([TreatNullAs=EmptyString] DOMString or TrustedScript) innerText;
     [Affects=Nothing, CEReactions, CustomElementCallbacks, RaisesException=Setter, MeasureAs=HTMLElementOuterText] attribute [TreatNullAs=EmptyString] DOMString outerText;
diff --git a/third_party/blink/renderer/core/html/html_slot_element.cc b/third_party/blink/renderer/core/html/html_slot_element.cc
index e0477248..62693d5 100644
--- a/third_party/blink/renderer/core/html/html_slot_element.cc
+++ b/third_party/blink/renderer/core/html/html_slot_element.cc
@@ -34,6 +34,7 @@
 #include "third_party/blink/renderer/core/css/style_change_reason.h"
 #include "third_party/blink/renderer/core/css/style_engine.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/dom/flat_tree_node_data.h"
 #include "third_party/blink/renderer/core/dom/mutation_observer.h"
 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/dom/node_traversal.h"
@@ -184,13 +185,11 @@
 
 void HTMLSlotElement::AppendAssignedNode(Node& host_child) {
   DCHECK(host_child.IsSlotable());
-  assigned_nodes_index_.insert(&host_child, assigned_nodes_.size());
   assigned_nodes_.push_back(&host_child);
 }
 
 void HTMLSlotElement::ClearAssignedNodes() {
   assigned_nodes_.clear();
-  assigned_nodes_index_.clear();
 }
 
 void HTMLSlotElement::ClearAssignedNodesAndFlatTreeChildren() {
@@ -198,6 +197,22 @@
   flat_tree_children_.clear();
 }
 
+void HTMLSlotElement::UpdateFlatTreeNodeDataForAssignedNodes() {
+  Node* previous = nullptr;
+  for (auto& current : assigned_nodes_) {
+    FlatTreeNodeData& flat_tree_node_data = current->EnsureFlatTreeNodeData();
+    flat_tree_node_data.SetAssignedSlot(this);
+    flat_tree_node_data.SetPreviousInAssignedNodes(previous);
+    if (previous) {
+      previous->GetFlatTreeNodeData().SetNextInAssignedNodes(current);
+    }
+    previous = current;
+  }
+  if (previous) {
+    previous->GetFlatTreeNodeData().SetNextInAssignedNodes(nullptr);
+  }
+}
+
 void HTMLSlotElement::RecalcFlatTreeChildren() {
   DCHECK(SupportsAssignment());
 
@@ -225,23 +240,15 @@
 Node* HTMLSlotElement::AssignedNodeNextTo(const Node& node) const {
   DCHECK(SupportsAssignment());
   ContainingShadowRoot()->GetSlotAssignment().RecalcAssignment();
-  auto it = assigned_nodes_index_.find(&node);
-  DCHECK(it != assigned_nodes_index_.end());
-  unsigned index = it->value;
-  if (index + 1 == assigned_nodes_.size())
-    return nullptr;
-  return assigned_nodes_[index + 1].Get();
+  DCHECK(assigned_nodes_.Contains(node));
+  return node.GetFlatTreeNodeData().NextInAssignedNodes();
 }
 
 Node* HTMLSlotElement::AssignedNodePreviousTo(const Node& node) const {
   DCHECK(SupportsAssignment());
   ContainingShadowRoot()->GetSlotAssignment().RecalcAssignment();
-  auto it = assigned_nodes_index_.find(&node);
-  DCHECK(it != assigned_nodes_index_.end());
-  unsigned index = it->value;
-  if (index == 0)
-    return nullptr;
-  return assigned_nodes_[index - 1].Get();
+  DCHECK(assigned_nodes_.Contains(node));
+  return node.GetFlatTreeNodeData().PreviousInAssignedNodes();
 }
 
 AtomicString HTMLSlotElement::GetName() const {
@@ -556,7 +563,6 @@
 
 void HTMLSlotElement::Trace(blink::Visitor* visitor) {
   visitor->Trace(assigned_nodes_);
-  visitor->Trace(assigned_nodes_index_);
   visitor->Trace(flat_tree_children_);
   visitor->Trace(assigned_nodes_candidates_);
   HTMLElement::Trace(visitor);
diff --git a/third_party/blink/renderer/core/html/html_slot_element.h b/third_party/blink/renderer/core/html/html_slot_element.h
index 3e944074..941c0e1 100644
--- a/third_party/blink/renderer/core/html/html_slot_element.h
+++ b/third_party/blink/renderer/core/html/html_slot_element.h
@@ -68,10 +68,14 @@
   Node* AssignedNodePreviousTo(const Node&) const;
 
   void AppendAssignedNode(Node&);
-  void ClearAssignedNodes();
 
   const HeapVector<Member<Node>> FlattenedAssignedNodes();
-  void RecalcFlatTreeChildren();
+
+  void WillRecalcAssignedNodes() { ClearAssignedNodes(); }
+  void DidRecalcAssignedNodes() {
+    UpdateFlatTreeNodeDataForAssignedNodes();
+    RecalcFlatTreeChildren();
+  }
 
   void AttachLayoutTree(AttachContext&) final;
   void DetachLayoutTree(const AttachContext& = AttachContext()) final;
@@ -134,10 +138,12 @@
 
   const HeapVector<Member<Node>>& GetDistributedNodes();
 
+  void RecalcFlatTreeChildren();
+  void UpdateFlatTreeNodeDataForAssignedNodes();
+  void ClearAssignedNodes();
   void ClearAssignedNodesAndFlatTreeChildren();
 
   HeapVector<Member<Node>> assigned_nodes_;
-  HeapHashMap<Member<const Node>, unsigned> assigned_nodes_index_;
   HeapVector<Member<Node>> flat_tree_children_;
 
   bool slotchange_event_enqueued_ = false;
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc
index aff2147b..7b1c8cc08 100644
--- a/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -1331,7 +1331,7 @@
 static inline bool IsChildHitTestCandidate(LayoutBox* box) {
   return box->Size().Height() &&
          box->StyleRef().Visibility() == EVisibility::kVisible &&
-         !box->IsOutOfFlowPositioned() && !box->IsLayoutFlowThread();
+         !box->IsFloatingOrOutOfFlowPositioned() && !box->IsLayoutFlowThread();
 }
 
 PositionWithAffinity LayoutBlock::PositionForPoint(
@@ -1373,9 +1373,6 @@
         continue;
       LayoutUnit child_logical_bottom =
           LogicalTopForChild(*child_box) + LogicalHeightForChild(*child_box);
-      if (child_box->IsLayoutBlockFlow())
-          child_logical_bottom += ToLayoutBlockFlow(child_box)->LowestFloatLogicalBottom();
-
       // We hit child if our click is above the bottom of its padding box (like
       // IE6/7 and FF3).
       if (point_in_logical_contents.Y() < child_logical_bottom ||
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index 3d911a9f..b889f5d 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -161,7 +161,8 @@
       // box to prevent having inline/block-mixed children.
       DCHECK(node->IsInline());
       LayoutInline* layout_inline = ToLayoutInline(node);
-      layout_inline->UpdateShouldCreateBoxFragment();
+      if (update_layout)
+        layout_inline->UpdateShouldCreateBoxFragment();
 
       builder->EnterInline(layout_inline);
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
index dd590a88..eb9131b 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -501,6 +501,10 @@
   return FragmentRange(nullptr, false);
 }
 
+const NGPaintFragment* NGPaintFragment::LastForSameLayoutObject() const {
+  return const_cast<NGPaintFragment*>(this)->LastForSameLayoutObject();
+}
+
 NGPaintFragment* NGPaintFragment::LastForSameLayoutObject() {
   NGPaintFragment* fragment = this;
   while (fragment->next_for_same_layout_object_)
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
index 47df43f81..b9ac581d 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
@@ -272,6 +272,7 @@
   // for a LayoutObject.
   static FragmentRange InlineFragmentsFor(const LayoutObject*);
 
+  const NGPaintFragment* LastForSameLayoutObject() const;
   NGPaintFragment* LastForSameLayoutObject();
 
   // Called when lines containing |child| is dirty.
diff --git a/third_party/blink/renderer/platform/fonts/font_metrics.cc b/third_party/blink/renderer/platform/fonts/font_metrics.cc
index cac33e0..abc03f4 100644
--- a/third_party/blink/renderer/platform/fonts/font_metrics.cc
+++ b/third_party/blink/renderer/platform/fonts/font_metrics.cc
@@ -33,7 +33,7 @@
 #include "third_party/blink/renderer/platform/fonts/font_platform_data.h"
 #include "third_party/blink/renderer/platform/fonts/vdmx_parser.h"
 
-#include <SkPaint.h>
+#include <SkFont.h>
 #include <SkTypeface.h>
 
 namespace blink {
@@ -49,13 +49,13 @@
     unsigned& visual_overflow_inflation_for_ascent,
     unsigned& visual_overflow_inflation_for_descent,
     const FontPlatformData& platform_data,
-    const SkPaint& paint,
+    const SkFont& font,
     bool subpixel_ascent_descent) {
-  SkTypeface* face = paint.getTypeface();
+  SkTypeface* face = font.getTypeface();
   DCHECK(face);
 
   SkFontMetrics metrics;
-  paint.getFontMetrics(&metrics);
+  font.getMetrics(&metrics);
 
   int vdmx_ascent = 0, vdmx_descent = 0;
   bool is_vdmx_valid = false;
@@ -66,8 +66,9 @@
   // done.  This code should be pushed into FreeType (hinted font metrics).
   static const uint32_t kVdmxTag = SkSetFourByteTag('V', 'D', 'M', 'X');
   int pixel_size = platform_data.size() + 0.5;
-  if (!paint.isAutohinted() && (paint.getHinting() == SkFontHinting::kFull ||
-                                paint.getHinting() == SkFontHinting::kNormal)) {
+  if (!font.isForceAutoHinting() &&
+      (font.getHinting() == SkFontHinting::kFull ||
+       font.getHinting() == SkFontHinting::kNormal)) {
     size_t vdmx_size = face->getTableSize(kVdmxTag);
     if (vdmx_size && vdmx_size < kMaxVDMXTableSize) {
       uint8_t* vdmx_table = (uint8_t*)WTF::Partitions::FastMalloc(
diff --git a/third_party/blink/renderer/platform/fonts/font_metrics.h b/third_party/blink/renderer/platform/fonts/font_metrics.h
index c994c46..e440a79c 100644
--- a/third_party/blink/renderer/platform/fonts/font_metrics.h
+++ b/third_party/blink/renderer/platform/fonts/font_metrics.h
@@ -25,7 +25,7 @@
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 
-#include <SkPaint.h>
+class SkFont;
 
 namespace blink {
 
@@ -168,7 +168,7 @@
       unsigned& visual_overflow_inflation_for_ascent,
       unsigned& visual_overflow_inflation_for_descent,
       const FontPlatformData&,
-      const SkPaint&,
+      const SkFont&,
       bool subpixel_ascent_descent = false);
 
  private:
diff --git a/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc b/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc
index 638e7633..4e01538 100644
--- a/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc
+++ b/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc
@@ -263,7 +263,7 @@
 }
 
 void OpenTypeVerticalData::GetVerticalTranslationsForGlyphs(
-    const SkPaint& paint,
+    const SkFont& font,
     const Glyph* glyphs,
     size_t count,
     float* out_xy_array) const {
@@ -304,7 +304,7 @@
       float top_side_bearing = top_side_bearing_f_unit * size_per_unit_;
 
       SkRect skiaBounds;
-      SkiaTextMetrics(&paint).GetSkiaBoundsForGlyph(glyph, &skiaBounds);
+      SkiaTextMetrics(font).GetSkiaBoundsForGlyph(glyph, &skiaBounds);
       FloatRect bounds(skiaBounds);
       out_xy_array[1] = bounds.Y() - top_side_bearing;
       continue;
diff --git a/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.h b/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.h
index 1096092..d6aa2710 100644
--- a/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.h
+++ b/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.h
@@ -33,10 +33,11 @@
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
-#include <SkPaint.h>
 #include <SkRefCnt.h>
 #include <SkTypeface.h>
 
+class SkFont;
+
 namespace blink {
 
 class PLATFORM_EXPORT OpenTypeVerticalData
@@ -55,7 +56,7 @@
   bool HasVerticalMetrics() const { return !advance_heights_.IsEmpty(); }
   float AdvanceHeight(Glyph) const;
 
-  void GetVerticalTranslationsForGlyphs(const SkPaint&,
+  void GetVerticalTranslationsForGlyphs(const SkFont&,
                                         const Glyph*,
                                         size_t,
                                         float* out_xy_array) const;
diff --git a/third_party/blink/renderer/platform/fonts/script_run_iterator.cc b/third_party/blink/renderer/platform/fonts/script_run_iterator.cc
index 012238f..86da0df 100644
--- a/third_party/blink/renderer/platform/fonts/script_run_iterator.cc
+++ b/third_party/blink/renderer/platform/fonts/script_run_iterator.cc
@@ -10,26 +10,6 @@
 
 namespace blink {
 
-namespace {
-
-// UScriptCode and OpenType script are not 1:1; specifically, both Hiragana and
-// Katakana map to 'kana' in OpenType. They will be mapped correctly in
-// HarfBuzz, but normalizing earlier helps to reduce splitting runs between
-// these scripts.
-// https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags
-inline UScriptCode getScriptForOpenType(UChar32 ch, UErrorCode* status) {
-  UScriptCode script = uscript_getScript(ch, status);
-  if (UNLIKELY(U_FAILURE(*status)))
-    return script;
-  if (UNLIKELY(script == USCRIPT_KATAKANA ||
-               script == USCRIPT_KATAKANA_OR_HIRAGANA)) {
-    return USCRIPT_HIRAGANA;
-  }
-  return script;
-}
-
-}  // namespace
-
 typedef ScriptData::PairedBracketType PairedBracketType;
 
 constexpr int ScriptRunIterator::kMaxScriptCount;
@@ -47,10 +27,6 @@
   // regardless of the capacity passed to the call. So count can be greater
   // than dst->size(), if a later version of the unicode data has more
   // than kMaxScriptCount items.
-
-  // |uscript_getScriptExtensions| do not need to be collated to
-  // USCRIPT_HIRAGANA because when ScriptExtensions contains Kana, it contains
-  // Hira as well, and Hira is always before Kana.
   int count = uscript_getScriptExtensions(ch, &dst[0], dst.size(), &status);
   if (status == U_BUFFER_OVERFLOW_ERROR) {
     // Allow this, we'll just use what we have.
@@ -59,7 +35,7 @@
     count = dst.size();
     status = U_ZERO_ERROR;
   }
-  UScriptCode primary_script = getScriptForOpenType(ch, &status);
+  UScriptCode primary_script = uscript_getScript(ch, &status);
 
   if (U_FAILURE(status)) {
     DLOG(ERROR) << "Could not get icu script data: " << status << " for 0x"
diff --git a/third_party/blink/renderer/platform/fonts/script_run_iterator_test.cc b/third_party/blink/renderer/platform/fonts/script_run_iterator_test.cc
index a792bdf..3e2a7a0 100644
--- a/third_party/blink/renderer/platform/fonts/script_run_iterator_test.cc
+++ b/third_party/blink/renderer/platform/fonts/script_run_iterator_test.cc
@@ -370,50 +370,6 @@
   CHECK_SCRIPT_RUNS({{"萬國碼", USCRIPT_HAN}});
 }
 
-struct JapaneseMixedScript {
-  const char* string;
-  // The expected primary_script when the string alone was evaluated.
-  UScriptCode script;
-} japanese_mixed_scripts[] = {{"あ", USCRIPT_HIRAGANA},
-                              // Katakana should be normalized to Hiragana
-                              {"ア", USCRIPT_HIRAGANA},
-                              // Script_Extensions=Hira Kana
-                              {"\u30FC", USCRIPT_HIRAGANA},
-                              // Script_Extensions=Hani Hira Kana
-                              {"\u303C", USCRIPT_HAN},
-                              // Script_Extensions=Bopo Hang Hani Hira Kana
-                              {"\u3003", USCRIPT_BOPOMOFO},
-                              // Script_Extensions=Bopo Hang Hani Hira Kana Yiii
-                              {"\u3001", USCRIPT_BOPOMOFO}};
-
-class JapaneseMixedScriptTest
-    : public ScriptRunIteratorTest,
-      public testing::WithParamInterface<JapaneseMixedScript> {};
-
-INSTANTIATE_TEST_CASE_P(ScriptRunIteratorTest,
-                        JapaneseMixedScriptTest,
-                        testing::ValuesIn(japanese_mixed_scripts));
-
-TEST_P(JapaneseMixedScriptTest, Data) {
-  const auto& data = GetParam();
-  std::string string(data.string);
-
-  CheckRuns({{string.data(), data.script}});
-
-  // If the string follows Hiragana or Katakana, or is followed by Hiragnaa or
-  // Katakana, it should be normalized as Hiragana.
-  std::string hiragana("か");
-  std::string katakana("カ");
-  CheckRuns({{(hiragana + string).data(), USCRIPT_HIRAGANA}});
-  CheckRuns({{(string + hiragana).data(), USCRIPT_HIRAGANA}});
-
-  CheckRuns({{(katakana + string).data(), USCRIPT_HIRAGANA}});
-  CheckRuns({{(string + katakana).data(), USCRIPT_HIRAGANA}});
-
-  CheckRuns({{(hiragana + string + katakana).data(), USCRIPT_HIRAGANA}});
-  CheckRuns({{(katakana + string + hiragana).data(), USCRIPT_HIRAGANA}});
-}
-
 // Close bracket without matching open is ignored
 TEST_F(ScriptRunIteratorTest, UnbalancedParens1) {
   CHECK_SCRIPT_RUNS(
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc
index 01a8341..e66dee9e 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc
@@ -131,7 +131,7 @@
       reinterpret_cast<HarfBuzzFontData*>(font_data);
   hb_position_t advance = 0;
 
-  SkiaTextMetrics(&hb_font_data->paint_)
+  SkiaTextMetrics(hb_font_data->font_)
       .GetGlyphWidthForHarfBuzz(glyph, &advance);
   return advance;
 }
@@ -146,7 +146,7 @@
                                                void* user_data) {
   HarfBuzzFontData* hb_font_data =
       reinterpret_cast<HarfBuzzFontData*>(font_data);
-  SkiaTextMetrics(&hb_font_data->paint_)
+  SkiaTextMetrics(hb_font_data->font_)
       .GetGlyphWidthForHarfBuzz(count, first_glyph, glyph_stride, first_advance,
                                 advance_stride);
 }
@@ -166,7 +166,7 @@
 
   float result[] = {0, 0};
   Glyph the_glyph = glyph;
-  vertical_data->GetVerticalTranslationsForGlyphs(hb_font_data->paint_,
+  vertical_data->GetVerticalTranslationsForGlyphs(hb_font_data->font_,
                                                   &the_glyph, 1, result);
   *x = SkiaTextMetrics::SkiaScalarToHarfBuzzPosition(-result[0]);
   *y = SkiaTextMetrics::SkiaScalarToHarfBuzzPosition(-result[1]);
@@ -201,7 +201,7 @@
   HarfBuzzFontData* hb_font_data =
       reinterpret_cast<HarfBuzzFontData*>(font_data);
 
-  SkTypeface* typeface = hb_font_data->paint_.getTypeface();
+  SkTypeface* typeface = hb_font_data->font_.getTypeface();
 
   const uint16_t glyphs[2] = {static_cast<uint16_t>(left_glyph),
                               static_cast<uint16_t>(right_glyph)};
@@ -224,7 +224,7 @@
   HarfBuzzFontData* hb_font_data =
       reinterpret_cast<HarfBuzzFontData*>(font_data);
 
-  SkiaTextMetrics(&hb_font_data->paint_)
+  SkiaTextMetrics(hb_font_data->font_)
       .GetGlyphExtentsForHarfBuzz(glyph, extents);
   return true;
 }
@@ -300,7 +300,7 @@
 }
 
 bool HarfBuzzFace::ShouldSubpixelPosition() {
-  return harfbuzz_font_data_->paint_.isSubpixelText();
+  return harfbuzz_font_data_->font_.isSubpixel();
 }
 
 static hb_font_funcs_t* HarfBuzzSkiaGetFontFuncs() {
@@ -431,11 +431,8 @@
 hb_font_t* HarfBuzzFace::GetScaledFont(
     scoped_refptr<UnicodeRangeSet> range_set,
     VerticalLayoutCallbacks vertical_layout) const {
-  SkPaint paint;
-  platform_data_->SetupSkPaint(&paint);
-  paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
   harfbuzz_font_data_->range_set_ = std::move(range_set);
-  harfbuzz_font_data_->UpdateFallbackMetricsAndScale(*platform_data_, paint,
+  harfbuzz_font_data_->UpdateFallbackMetricsAndScale(*platform_data_,
                                                      vertical_layout);
 
   int scale =
@@ -443,7 +440,7 @@
   hb_font_set_scale(unscaled_font_, scale, scale);
   hb_font_set_ptem(unscaled_font_, platform_data_->size() / kCssPixelsPerPoint);
 
-  SkTypeface* typeface = harfbuzz_font_data_->paint_.getTypeface();
+  SkTypeface* typeface = harfbuzz_font_data_->font_.getTypeface();
   int axis_count = typeface->getVariationDesignPosition(nullptr, 0);
   if (axis_count > 0) {
     Vector<SkFontArguments::VariationPosition::Coordinate> axis_values;
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h
index 69fa5f1..f364596 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h
@@ -40,7 +40,7 @@
 
  public:
   HarfBuzzFontData()
-      : paint_(),
+      : font_(),
         space_in_gpos_(SpaceGlyphInOpenTypeTables::Unknown),
         space_in_gsub_(SpaceGlyphInOpenTypeTables::Unknown),
         vertical_data_(nullptr),
@@ -51,19 +51,19 @@
   // layout information is found from the font.
   void UpdateFallbackMetricsAndScale(
       const FontPlatformData& platform_data,
-      const SkPaint& paint,
       HarfBuzzFace::VerticalLayoutCallbacks vertical_layout) {
     float ascent = 0;
     float descent = 0;
     unsigned dummy_ascent_inflation = 0;
     unsigned dummy_descent_inflation = 0;
 
-    paint_ = paint;
+    font_ = SkFont();
+    platform_data.SetupSkFont(&font_);
 
     if (UNLIKELY(vertical_layout == HarfBuzzFace::PrepareForVerticalLayout)) {
       FontMetrics::AscentDescentWithHacks(
           ascent, descent, dummy_ascent_inflation, dummy_descent_inflation,
-          platform_data, paint);
+          platform_data, font_);
       ascent_fallback_ = ascent;
       // Simulate the rounding that FontMetrics does so far for returning the
       // integer Height()
@@ -87,7 +87,7 @@
     if (size_per_unit_ != kInvalidFallbackMetricsValue)
       return size_per_unit_;
     int units_per_em = typeface.getUnitsPerEm();
-    size_per_unit_ = paint_.getTextSize() / units_per_em;
+    size_per_unit_ = font_.getSize() / units_per_em;
     return size_per_unit_;
   }
 
@@ -98,14 +98,14 @@
       DCHECK_NE(size_per_unit_, kInvalidFallbackMetricsValue);
 
       vertical_data_ =
-          OpenTypeVerticalData::CreateUnscaled(paint_.refTypeface());
+          OpenTypeVerticalData::CreateUnscaled(font_.refTypeface());
     }
     vertical_data_->SetScaleAndFallbackMetrics(size_per_unit_, ascent_fallback_,
                                                height_fallback_);
     return vertical_data_;
   }
 
-  SkPaint paint_;
+  SkFont font_;
 
   // Capture these scaled fallback metrics from FontPlatformData so that a
   // OpenTypeVerticalData object can be constructed from them when needed.
diff --git a/third_party/blink/renderer/platform/fonts/simple_font_data.cc b/third_party/blink/renderer/platform/fonts/simple_font_data.cc
index 3f48393..d8ca821 100644
--- a/third_party/blink/renderer/platform/fonts/simple_font_data.cc
+++ b/third_party/blink/renderer/platform/fonts/simple_font_data.cc
@@ -79,17 +79,16 @@
 
   SkFontMetrics metrics;
 
-  paint_ = SkPaint();
-  platform_data_.SetupSkPaint(&paint_);
-  paint_.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-  paint_.getFontMetrics(&metrics);
+  font_ = SkFont();
+  platform_data_.SetupSkFont(&font_);
+  font_.getMetrics(&metrics);
 
   float ascent;
   float descent;
 
   FontMetrics::AscentDescentWithHacks(
       ascent, descent, visual_overflow_inflation_for_ascent_,
-      visual_overflow_inflation_for_descent_, platform_data_, paint_,
+      visual_overflow_inflation_for_descent_, platform_data_, font_,
       subpixel_ascent_descent);
 
   font_metrics_.SetAscent(ascent);
@@ -161,7 +160,7 @@
   }
 #endif
 
-  SkTypeface* face = paint_.getTypeface();
+  SkTypeface* face = font_.getTypeface();
   DCHECK(face);
   if (int units_per_em = face->getUnitsPerEm())
     font_metrics_.SetUnitsPerEm(units_per_em);
@@ -349,7 +348,7 @@
   static_assert(sizeof(glyph) == 2, "Glyph id should not be truncated.");
 
   SkRect bounds;
-  SkiaTextMetrics(&paint_).GetSkiaBoundsForGlyph(glyph, &bounds);
+  SkiaTextMetrics(font_).GetSkiaBoundsForGlyph(glyph, &bounds);
   return FloatRect(bounds);
 }
 
@@ -361,7 +360,7 @@
     return;
 
   DCHECK_EQ(bounds->size(), glyphs.size());
-  SkiaTextMetrics(&paint_).GetSkiaBoundsForGlyphs(glyphs, bounds->data());
+  SkiaTextMetrics(font_).GetSkiaBoundsForGlyphs(glyphs, bounds->data());
 }
 
 float SimpleFontData::PlatformWidthForGlyph(Glyph glyph) const {
@@ -370,7 +369,7 @@
 
   static_assert(sizeof(glyph) == 2, "Glyph id should not be truncated.");
 
-  return SkiaTextMetrics(&paint_).GetSkiaWidthForGlyph(glyph);
+  return SkiaTextMetrics(font_).GetSkiaWidthForGlyph(glyph);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/simple_font_data.h b/third_party/blink/renderer/platform/fonts/simple_font_data.h
index cc4a85d2..055acaf 100644
--- a/third_party/blink/renderer/platform/fonts/simple_font_data.h
+++ b/third_party/blink/renderer/platform/fonts/simple_font_data.h
@@ -24,7 +24,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SIMPLE_FONT_DATA_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SIMPLE_FONT_DATA_H_
 
-#include <SkPaint.h>
+#include <SkFont.h>
 
 #include <memory>
 #include <utility>
@@ -170,7 +170,7 @@
   float avg_char_width_;
 
   FontPlatformData platform_data_;
-  SkPaint paint_;
+  SkFont font_;
 
   Glyph space_glyph_;
   float space_width_;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index f354baad..16d9f3e 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -399,6 +399,7 @@
     {
       // http://crbug.com/905922
       name: "ElementInternals",
+      status: "test",
     },
     {
       // https://crbug.com/879270
diff --git a/third_party/glfw/README.chromium b/third_party/glfw/README.chromium
index 6036577..eb4f2dc9 100644
--- a/third_party/glfw/README.chromium
+++ b/third_party/glfw/README.chromium
@@ -2,7 +2,7 @@
 Short Name: GLFW
 URL: https://github.com/glfw/glfw
 Version: 3.3-dev
-Revision: 096efdf798896cff80a0b2db08d7398b703406fe
+Revision: 2de2589f910b1a85905f425be4d32f33cec092df
 Security Critical: no
 License: Zlib
 License File: NOT_SHIPPED
diff --git a/tools/clang/blink_gc_plugin/BadPatternFinder.cpp b/tools/clang/blink_gc_plugin/BadPatternFinder.cpp
index f3bec427..ef1da662 100644
--- a/tools/clang/blink_gc_plugin/BadPatternFinder.cpp
+++ b/tools/clang/blink_gc_plugin/BadPatternFinder.cpp
@@ -5,6 +5,7 @@
 #include "BadPatternFinder.h"
 #include "DiagnosticsReporter.h"
 
+#include <algorithm>
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
@@ -82,6 +83,62 @@
   DiagnosticsReporter& diagnostics_;
 };
 
+class MissingMixinMarker : public MatchFinder::MatchCallback {
+ public:
+  explicit MissingMixinMarker(clang::ASTContext& ast_context,
+                              DiagnosticsReporter& diagnostics)
+      : ast_context_(ast_context), diagnostics_(diagnostics) {}
+
+  void Register(MatchFinder& match_finder) {
+    auto class_missing_mixin_marker = cxxRecordDecl(
+        decl().bind("bad_class"),
+        // Definition of a garbage-collected class
+        isDefinition(),
+        isDerivedFrom(cxxRecordDecl(decl().bind("gc_base_class"),
+                                    hasName("::blink::GarbageCollected"))),
+        // ...which derives some mixin...
+        isDerivedFrom(cxxRecordDecl(decl().bind("mixin_base_class"),
+                                    hasName("::blink::GarbageCollectedMixin"))),
+        // ...and doesn't use USING_GARBAGE_COLLECTED_MIXIN
+        unless(isSameOrDerivedFrom(
+            has(fieldDecl(hasName("mixin_constructor_marker_"))))),
+        // ...and might end up actually being constructed
+        unless(hasMethod(isPure())), unless(matchesName("::SameSizeAs")));
+    match_finder.addDynamicMatcher(class_missing_mixin_marker, this);
+  }
+
+  void run(const MatchFinder::MatchResult& result) {
+    auto* bad_class = result.Nodes.getNodeAs<clang::CXXRecordDecl>("bad_class");
+    auto* gc_base_class =
+        result.Nodes.getNodeAs<clang::CXXRecordDecl>("gc_base_class");
+    auto* mixin_base_class =
+        result.Nodes.getNodeAs<clang::CXXRecordDecl>("mixin_base_class");
+
+    clang::CXXBasePaths paths;
+    if (!bad_class->isDerivedFrom(mixin_base_class, paths))
+      return;
+    const auto& path = paths.front();
+
+    // It's most useful to describe the most derived "mixin" class (i.e. which
+    // does not derive the concrete GarbageCollected base).
+    auto mixin_it = std::find_if(
+        path.begin(), path.end(),
+        [gc_base_class](const clang::CXXBasePathElement& path_element) {
+          return !path_element.Class->isDerivedFrom(gc_base_class);
+        });
+    const clang::CXXRecordDecl* mixin_class = mixin_it->Class;
+    diagnostics_.MissingMixinMarker(bad_class, mixin_class, path.begin()->Base);
+
+    ++mixin_it;
+    for (auto it = path.begin() + 1; it != mixin_it; ++it)
+      diagnostics_.MissingMixinMarkerNote(it->Base);
+  }
+
+ private:
+  clang::ASTContext& ast_context_;
+  DiagnosticsReporter& diagnostics_;
+};
+
 }  // namespace
 
 void FindBadPatterns(clang::ASTContext& ast_context,
@@ -94,5 +151,8 @@
   OptionalGarbageCollectedMatcher optional_gc(diagnostics);
   optional_gc.Register(match_finder);
 
+  MissingMixinMarker missing_mixin_marker(ast_context, diagnostics);
+  missing_mixin_marker.Register(match_finder);
+
   match_finder.matchAST(ast_context);
 }
diff --git a/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp b/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp
index 032f3ff..65dba9b 100644
--- a/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp
+++ b/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp
@@ -162,6 +162,13 @@
     "[blink-gc] Disallowed construction of %0 found; %1 is a garbage-collected "
     "type. optional cannot hold garbage-collected objects.";
 
+const char kMissingMixinMarker[] =
+    "[blink-gc] Garbage-collected class %0 derives mixin class %1. "
+    "You must add USING_GARBAGE_COLLECTED_MIXIN(%2).";
+
+const char kMissingMixinMarkerNote[] =
+    "[blink-gc] Mixin base class derived here:";
+
 } // namespace
 
 DiagnosticBuilder DiagnosticsReporter::ReportDiagnostic(
@@ -275,6 +282,10 @@
       diagnostic_.getCustomDiagID(getErrorLevel(), kUniquePtrUsedWithGC);
   diag_optional_used_with_gc_ =
       diagnostic_.getCustomDiagID(getErrorLevel(), kOptionalUsedWithGC);
+  diag_missing_mixin_marker_ =
+      diagnostic_.getCustomDiagID(getErrorLevel(), kMissingMixinMarker);
+  diag_missing_mixin_marker_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kMissingMixinMarkerNote);
 }
 
 bool DiagnosticsReporter::hasErrorOccurred() const
@@ -600,3 +611,18 @@
   ReportDiagnostic(expr->getBeginLoc(), diag_optional_used_with_gc_)
       << optional << gc_type << expr->getSourceRange();
 }
+
+void DiagnosticsReporter::MissingMixinMarker(
+    const clang::CXXRecordDecl* bad_class,
+    const clang::CXXRecordDecl* mixin_class,
+    const clang::CXXBaseSpecifier* first_base) {
+  ReportDiagnostic(first_base->getBaseTypeLoc(), diag_missing_mixin_marker_)
+      << bad_class << mixin_class << bad_class->getName()
+      << first_base->getSourceRange();
+}
+
+void DiagnosticsReporter::MissingMixinMarkerNote(
+    const clang::CXXBaseSpecifier* base) {
+  ReportDiagnostic(base->getBaseTypeLoc(), diag_missing_mixin_marker_note_)
+      << base->getSourceRange();
+}
diff --git a/tools/clang/blink_gc_plugin/DiagnosticsReporter.h b/tools/clang/blink_gc_plugin/DiagnosticsReporter.h
index 512874d6..2d8b0c7 100644
--- a/tools/clang/blink_gc_plugin/DiagnosticsReporter.h
+++ b/tools/clang/blink_gc_plugin/DiagnosticsReporter.h
@@ -86,6 +86,10 @@
   void OptionalUsedWithGC(const clang::Expr* expr,
                           const clang::CXXRecordDecl* optional,
                           const clang::CXXRecordDecl* gc_type);
+  void MissingMixinMarker(const clang::CXXRecordDecl* bad_class,
+                          const clang::CXXRecordDecl* mixin_class,
+                          const clang::CXXBaseSpecifier* first_base);
+  void MissingMixinMarkerNote(const clang::CXXBaseSpecifier* base);
 
  private:
   clang::DiagnosticBuilder ReportDiagnostic(
@@ -150,6 +154,8 @@
 
   unsigned diag_unique_ptr_used_with_gc_;
   unsigned diag_optional_used_with_gc_;
+  unsigned diag_missing_mixin_marker_;
+  unsigned diag_missing_mixin_marker_note_;
 };
 
 #endif // TOOLS_BLINK_GC_PLUGIN_DIAGNOSTICS_REPORTER_H_
diff --git a/tools/clang/blink_gc_plugin/tests/heap/stubs.h b/tools/clang/blink_gc_plugin/tests/heap/stubs.h
index 3f2797e..844db9a 100644
--- a/tools/clang/blink_gc_plugin/tests/heap/stubs.h
+++ b/tools/clang/blink_gc_plugin/tests/heap/stubs.h
@@ -192,10 +192,11 @@
 #define GC_PLUGIN_IGNORE(bug)                           \
     __attribute__((annotate("blink_gc_plugin_ignore")))
 
-#define USING_GARBAGE_COLLECTED_MIXIN(type)                     \
-public:                                                         \
-    virtual void AdjustAndMark(Visitor*) const override { }     \
-    virtual bool IsHeapObjectAlive(Visitor*) const override { return 0; }
+#define USING_GARBAGE_COLLECTED_MIXIN(type)                             \
+ public:                                                                \
+  virtual void AdjustAndMark(Visitor*) const override {}                \
+  virtual bool IsHeapObjectAlive(Visitor*) const override { return 0; } \
+  void* mixin_constructor_marker_;
 
 #define EAGERLY_FINALIZED() typedef int IsEagerlyFinalizedMarker
 
diff --git a/tools/clang/blink_gc_plugin/tests/missing_mixin_marker.cpp b/tools/clang/blink_gc_plugin/tests/missing_mixin_marker.cpp
new file mode 100644
index 0000000..a10e767
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/missing_mixin_marker.cpp
@@ -0,0 +1,58 @@
+// 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 "heap/stubs.h"
+
+namespace blink {
+
+class Mixin : public GarbageCollectedMixin {
+ public:
+  virtual void Trace(Visitor*) {}
+};
+
+// Class derived from a mixin needs USING_GARBAGE_COLLECTED_MIXIN.
+class Derived : public GarbageCollected<Derived>, public Mixin {
+  virtual void Trace(Visitor* visitor) override { Mixin::Trace(visitor); }
+};
+
+template <typename T>
+class Supplement : public GarbageCollectedMixin {
+ public:
+  virtual void Trace(Visitor*) {}
+};
+
+// Class derived from a mixin template needs USING_GARBAGE_COLLECTED_MIXIN.
+class MySupplement : public GarbageCollectedFinalized<MySupplement>,
+                     public Supplement<Derived> {
+  virtual void Trace(Visitor* visitor) override { Supplement::Trace(visitor); }
+};
+
+// This is the right way to do it.
+// We should get no warning either here or at a forward declaration.
+class GoodDerived : public GarbageCollected<GoodDerived>, public Mixin {
+  USING_GARBAGE_COLLECTED_MIXIN(GoodDerived);
+};
+class GoodDerived;
+
+// Abstract classes (i.e. ones with pure virtual methods) can't be constructed
+// and so it's assumed their derived classes will have
+// USING_GARBAGE_COLLECTED_MIXIN.
+class PureVirtual : public GarbageCollected<PureVirtual>, public Mixin {
+ public:
+  virtual void Foo() = 0;
+};
+// ...but failure to do so is still bad. Warn here.
+class PureVirtualDerived : public PureVirtual {
+ public:
+  void Foo() override {}
+};
+
+// And there's an exception for "same size" classes, which are just used for
+// assertions. This should not warn.
+class SameSizeAsGoodDerived : public GarbageCollected<SameSizeAsGoodDerived>,
+                              public Mixin {
+  char same_size_as_mixin_marker_[1];
+};
+
+}  // namespace blink
diff --git a/tools/clang/blink_gc_plugin/tests/missing_mixin_marker.txt b/tools/clang/blink_gc_plugin/tests/missing_mixin_marker.txt
new file mode 100644
index 0000000..692f7d6
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/missing_mixin_marker.txt
@@ -0,0 +1,22 @@
+missing_mixin_marker.cpp:15:58: warning: [blink-gc] Garbage-collected class 'Derived' derives mixin class 'Mixin'. You must add USING_GARBAGE_COLLECTED_MIXIN(Derived).
+class Derived : public GarbageCollected<Derived>, public Mixin {
+                                                  ~~~~~~~^~~~~
+missing_mixin_marker.cpp:9:22: note: [blink-gc] Mixin base class derived here:
+class Mixin : public GarbageCollectedMixin {
+              ~~~~~~~^~~~~~~~~~~~~~~~~~~~~
+missing_mixin_marker.cpp:27:29: warning: [blink-gc] Garbage-collected class 'MySupplement' derives mixin class 'Supplement<blink::Derived>'. You must add USING_GARBAGE_COLLECTED_MIXIN(MySupplement).
+                     public Supplement<Derived> {
+                     ~~~~~~~^~~~~~~~~~~~~~~~~~~
+missing_mixin_marker.cpp:20:27: note: [blink-gc] Mixin base class derived here:
+class Supplement : public GarbageCollectedMixin {
+                   ~~~~~~~^~~~~~~~~~~~~~~~~~~~~
+missing_mixin_marker.cpp:46:35: warning: [blink-gc] Garbage-collected class 'PureVirtualDerived' derives mixin class 'Mixin'. You must add USING_GARBAGE_COLLECTED_MIXIN(PureVirtualDerived).
+class PureVirtualDerived : public PureVirtual {
+                           ~~~~~~~^~~~~~~~~~~
+missing_mixin_marker.cpp:41:66: note: [blink-gc] Mixin base class derived here:
+class PureVirtual : public GarbageCollected<PureVirtual>, public Mixin {
+                                                          ~~~~~~~^~~~~
+missing_mixin_marker.cpp:9:22: note: [blink-gc] Mixin base class derived here:
+class Mixin : public GarbageCollectedMixin {
+              ~~~~~~~^~~~~~~~~~~~~~~~~~~~~
+3 warnings generated.
diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py
index 0ca9598..025b007 100755
--- a/tools/clang/scripts/package.py
+++ b/tools/clang/scripts/package.py
@@ -281,6 +281,11 @@
         'lib/clang/*/lib/linux/libclang_rt.asan_cxx-x86_64.a',
         'lib/clang/*/lib/linux/libclang_rt.asan_cxx-x86_64.a.syms',
 
+        # AddressSanitizer Android runtime.
+        'lib/clang/*/lib/linux/libclang_rt.asan-aarch64-android.so',
+        'lib/clang/*/lib/linux/libclang_rt.asan-arm-android.so',
+        'lib/clang/*/lib/linux/libclang_rt.asan-i686-android.so',
+
         # Fuzzing instrumentation (-fsanitize=fuzzer-no-link).
         'lib/clang/*/lib/linux/libclang_rt.fuzzer_no_main-x86_64.a',
 
@@ -295,6 +300,8 @@
         # Profile runtime (used by profiler and code coverage).
         'lib/clang/*/lib/linux/libclang_rt.profile-i386.a',
         'lib/clang/*/lib/linux/libclang_rt.profile-x86_64.a',
+        'lib/clang/*/lib/linux/libclang_rt.profile-aarch64-android.a',
+        'lib/clang/*/lib/linux/libclang_rt.profile-arm-android.a',
 
         # ThreadSanitizer C runtime (pure C won't link with *_cxx).
         'lib/clang/*/lib/linux/libclang_rt.tsan-x86_64.a',
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 5d566ce..96ecf6b 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -10099,6 +10099,14 @@
   </description>
 </action>
 
+<action name="ManualFallback_CreditCard_OpenManageCreditCard">
+  <owner>javierrobles@chromium.org</owner>
+  <description>
+    The user tapped on &quot;Manage credit cards&quot; on the Password Manual
+    Fallback view.
+  </description>
+</action>
+
 <action name="ManualFallback_OpenCreditCard">
   <owner>javierrobles@chromium.org</owner>
   <description>The user opened Credit Card Manual Fallback view.</description>
@@ -10144,6 +10152,14 @@
   </description>
 </action>
 
+<action name="ManualFallback_Profiles_OpenManageProfiles">
+  <owner>javierrobles@chromium.org</owner>
+  <description>
+    The user tapped on &quot;Manage addresses&quot; on the Password Manual
+    Fallback view.
+  </description>
+</action>
+
 <action name="MaxButton_Clk_ExitFS">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 63a2ad5..0aabee49 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -29274,6 +29274,7 @@
   <int value="-1832221649" label="disable-out-of-process-pac"/>
   <int value="-1826649921" label="ContextualSuggestionsButton:disabled"/>
   <int value="-1821058653" label="enable-delay-agnostic-aec"/>
+  <int value="-1818947212" label="OutOfBlinkCors:disabled"/>
   <int value="-1817209284" label="PayWithGoogleV1:enabled"/>
   <int value="-1816066138" label="CastAllowAllIPs:enabled"/>
   <int value="-1812579951" label="ContentSuggestionsCategoryRanker:enabled"/>
@@ -31251,6 +31252,7 @@
   <int value="1838990777" label="V8Future:enabled"/>
   <int value="1839740266" label="LocationHardReload:disabled"/>
   <int value="1842219851" label="enable-incognito-window-counter"/>
+  <int value="1843088575" label="OutOfBlinkCors:enabled"/>
   <int value="1844110073" label="enable-app-view"/>
   <int value="1845131710" label="Newblue:enabled"/>
   <int value="1847024354" label="enable-hotword-hardware"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index d7ef941..05acf8b 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -100598,6 +100598,14 @@
   </summary>
 </histogram>
 
+<histogram name="SessionStorageContext.OnConnectionDestroyed" enum="Boolean">
+  <owner>dmurph@chromium.org</owner>
+  <owner>dullweber@chromium.org</owner>
+  <summary>
+    Recorded when the database connection is closed unexpectedly.
+  </summary>
+</histogram>
+
 <histogram name="SessionStorageContext.OpenError" enum="LocalStorageOpenError">
   <owner>dmurph@chromium.org</owner>
   <summary>
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv
index ff916d9..b25e14a 100644
--- a/tools/perf/benchmark.csv
+++ b/tools/perf/benchmark.csv
@@ -7,7 +7,7 @@
 blink_perf.bindings,"jbroman@chromium.org, yukishiino@chromium.org, haraken@chromium.org",Blink>Bindings,https://bit.ly/blink-perf-benchmarks,
 blink_perf.canvas,"aaronhk@chromium.org, fserb@chromium.org",Blink>Canvas,https://bit.ly/blink-perf-benchmarks,
 blink_perf.css,"futhark@chromium.org, andruud@chromium.org",Blink>CSS,https://bit.ly/blink-perf-benchmarks,
-blink_perf.dom,"hayato@chromium.org, tkent@chromium.org, yosin@chromium.org",Blink>DOM,https://bit.ly/blink-perf-benchmarks,
+blink_perf.dom,"hayato@chromium.org, tkent@chromium.org",Blink>DOM,https://bit.ly/blink-perf-benchmarks,
 blink_perf.events,hayato@chromium.org,Blink>DOM,https://bit.ly/blink-perf-benchmarks,
 blink_perf.image_decoder,cblume@chromium.org,Internals>Images>Codecs,https://bit.ly/blink-perf-benchmarks,
 blink_perf.layout,eae@chromium.org,,https://bit.ly/blink-perf-benchmarks,
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index c32c1fe..8c52292 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -434,8 +434,7 @@
     return story_set
 
 @benchmark.Info(emails=['hayato@chromium.org',
-                        'tkent@chromium.org',
-                        'yosin@chromium.org'],
+                        'tkent@chromium.org'],
                 component='Blink>DOM',
                 documentation_url='https://bit.ly/blink-perf-benchmarks')
 class BlinkPerfDOM(_BlinkPerfBenchmark):
diff --git a/tools/perf/benchmarks/system_health_smoke_test.py b/tools/perf/benchmarks/system_health_smoke_test.py
index 00fb37d..e82d45a0 100644
--- a/tools/perf/benchmarks/system_health_smoke_test.py
+++ b/tools/perf/benchmarks/system_health_smoke_test.py
@@ -91,6 +91,7 @@
   'system_health.memory_desktop/load:media:google_images',
   'system_health.memory_desktop/load:media:imgur',
   'system_health.memory_desktop/load:media:soundcloud',
+  'system_health.memory_desktop/load:media:youtube',
   'system_health.memory_desktop/load:news:cnn',
   'system_health.memory_desktop/load:news:wikipedia',
   'system_health.memory_desktop/load:search:baidu',
@@ -105,6 +106,7 @@
   'system_health.memory_mobile/load:media:flickr',
   'system_health.memory_mobile/load:media:google_images',
   'system_health.memory_mobile/load:media:imgur',
+  'system_health.memory_mobile/load:media:youtube',
   'system_health.memory_mobile/load:news:wikipedia',
   'system_health.memory_mobile/load:search:baidu',
   'system_health.memory_mobile/load:search:ebay',
diff --git a/tools/perf/page_sets/data/system_health_desktop.json b/tools/perf/page_sets/data/system_health_desktop.json
index c08c7e4..6759539 100644
--- a/tools/perf/page_sets/data/system_health_desktop.json
+++ b/tools/perf/page_sets/data/system_health_desktop.json
@@ -174,6 +174,9 @@
             "mac": "system_health_desktop_040.wprgo",
             "win": "system_health_desktop_047.wprgo"
         },
+        "load:media:youtube:2018": {
+            "DEFAULT": "system_health_desktop_cef8441ac0.wprgo"
+        },
         "load:news:bbc": {
             "DEFAULT": "system_health_desktop_002.wprgo"
         },
diff --git a/tools/perf/page_sets/data/system_health_desktop_cef8441ac0.wprgo.sha1 b/tools/perf/page_sets/data/system_health_desktop_cef8441ac0.wprgo.sha1
new file mode 100644
index 0000000..e1f6241
--- /dev/null
+++ b/tools/perf/page_sets/data/system_health_desktop_cef8441ac0.wprgo.sha1
@@ -0,0 +1 @@
+d52f8fc9e9620b964cbbf004eee7322a81dda6c8
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/system_health_mobile.json b/tools/perf/page_sets/data/system_health_mobile.json
index 9f8e29de..9368b1d 100644
--- a/tools/perf/page_sets/data/system_health_mobile.json
+++ b/tools/perf/page_sets/data/system_health_mobile.json
@@ -156,6 +156,9 @@
         "load:media:youtube": {
             "DEFAULT": "system_health_mobile_003.wprgo"
         },
+        "load:media:youtube:2018": {
+            "DEFAULT": "system_health_mobile_2d7e2af174.wprgo"
+        },
         "load:news:bbc": {
             "DEFAULT": "system_health_mobile_002.wprgo"
         },
diff --git a/tools/perf/page_sets/data/system_health_mobile_2d7e2af174.wprgo.sha1 b/tools/perf/page_sets/data/system_health_mobile_2d7e2af174.wprgo.sha1
new file mode 100644
index 0000000..ed9576c
--- /dev/null
+++ b/tools/perf/page_sets/data/system_health_mobile_2d7e2af174.wprgo.sha1
@@ -0,0 +1 @@
+2d7e2af174d161596ba4cd6ca031cfd21047ef80
\ No newline at end of file
diff --git a/tools/perf/page_sets/system_health/loading_stories.py b/tools/perf/page_sets/system_health/loading_stories.py
index 4d1dd71..ba231ec 100644
--- a/tools/perf/page_sets/system_health/loading_stories.py
+++ b/tools/perf/page_sets/system_health/loading_stories.py
@@ -352,6 +352,14 @@
           story_tags.YEAR_2016]
 
 
+class LoadYouTubeStory2018(_LoadingStory):
+  # No way to disable autoplay on desktop.
+  NAME = 'load:media:youtube:2018'
+  URL = 'https://www.youtube.com/watch?v=QGfhS1hfTWw&autoplay=false'
+  TAGS = [story_tags.EMERGING_MARKET, story_tags.HEALTH_CHECK,
+          story_tags.YEAR_2018]
+
+
 class LoadDailymotionStory(_LoadingStory):
   # The side panel with related videos doesn't show on desktop due to
   # https://github.com/chromium/web-page-replay/issues/74.
diff --git a/ui/file_manager/file_manager/background/js/test_util.js b/ui/file_manager/file_manager/background/js/test_util.js
index c57883df..6b7b803 100644
--- a/ui/file_manager/file_manager/background/js/test_util.js
+++ b/ui/file_manager/file_manager/background/js/test_util.js
@@ -91,7 +91,6 @@
  */
 test.util.sync.selectFile = function(contentWindow, filename) {
   var rows = contentWindow.document.querySelectorAll('#detail-table li');
-  test.util.sync.focus(contentWindow, '#file-list');
   test.util.sync.fakeKeyDown(
       contentWindow, '#file-list', 'Home', false, false, false);
   for (var index = 0; index < rows.length; ++index) {
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
index 4b2088e..18441e4 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
@@ -669,6 +669,14 @@
  * @private
  */
 FileGrid.prototype.onSplice_ = function() {
+  // When adjusting search parameters, |dataModel| is transiently empty.
+  // Updating whether image-dominant is active at these times can cause spurious
+  // changes. Avoid this problem by not updating whether image-dominant is
+  // active when |dataModel| is empty.
+  if (this.dataModel.getFileCount() == 0 &&
+      this.dataModel.getFolderCount() == 0) {
+    return;
+  }
   this.classList.toggle('image-dominant', this.dataModel.isImageDominant());
 };
 
diff --git a/ui/file_manager/integration_tests/file_manager/background.js b/ui/file_manager/integration_tests/file_manager/background.js
index f6c45eb..503640b 100644
--- a/ui/file_manager/integration_tests/file_manager/background.js
+++ b/ui/file_manager/integration_tests/file_manager/background.js
@@ -246,7 +246,6 @@
   ENTRIES.hello,
   ENTRIES.teamDriveA,
   ENTRIES.teamDriveAFile,
-  ENTRIES.teamDriveADirectory,
   ENTRIES.teamDriveAHostedFile,
   ENTRIES.teamDriveB,
   ENTRIES.teamDriveBFile,
diff --git a/ui/file_manager/integration_tests/file_manager/share_and_manage_dialog.js b/ui/file_manager/integration_tests/file_manager/share_and_manage_dialog.js
index 58d0ee6d..3e2efb4 100644
--- a/ui/file_manager/integration_tests/file_manager/share_and_manage_dialog.js
+++ b/ui/file_manager/integration_tests/file_manager/share_and_manage_dialog.js
@@ -9,32 +9,19 @@
  *
  * @param {!string} path Path of the file or directory to be shared.
  * @param {!string} url Expected URL for the browser to visit.
- * @param {!string|undefined} teamDrive If set, the team drive to switch to.
  */
-function shareWithOthersExpectBrowserURL(path, url, teamDrive = undefined) {
+function shareWithOthersExpectBrowserURL(path, url) {
   let appId;
 
   StepsRunner.run([
     // Open Files app on Drive.
     function() {
       setupAndWaitUntilReady(
-          null, RootPath.DRIVE, this.next, [],
-          BASIC_DRIVE_ENTRY_SET.concat(TEAM_DRIVE_ENTRY_SET));
-    },
-    // Navigate to the specified team drive if one is specified.
-    function(results) {
-      appId = results.windowId;
-      if (!teamDrive) {
-        this.next();
-        return;
-      }
-      remoteCall
-          .navigateWithDirectoryTree(
-              appId, `/team_drives/${teamDrive}`, 'Team Drives', 'drive')
-          .then(this.next);
+          null, RootPath.DRIVE, this.next, [], BASIC_DRIVE_ENTRY_SET);
     },
     // Select the given |path|.
-    function() {
+    function(results) {
+      appId = results.windowId;
       remoteCall.callRemoteTestUtil('selectFile', appId, [path], this.next);
     },
     // Wait for the entry to be selected.
@@ -93,32 +80,19 @@
  *
  * @param {!string} path Path of the file or directory to be managed.
  * @param {!string} url Expected URL for the browser to visit.
- * @param {!string|undefined} teamDrive If set, the team drive to switch to.
  */
-function manageWithDriveExpectBrowserURL(path, url, teamDrive = undefined) {
+function manageWithDriveExpectBrowserURL(path, url) {
   let appId;
 
   StepsRunner.run([
     // Open Files app on Drive.
     function() {
       setupAndWaitUntilReady(
-          null, RootPath.DRIVE, this.next, [],
-          BASIC_DRIVE_ENTRY_SET.concat(TEAM_DRIVE_ENTRY_SET));
-    },
-    // Navigate to the specified team drive if one is specified.
-    function(results) {
-      appId = results.windowId;
-      if (!teamDrive) {
-        this.next();
-        return;
-      }
-      remoteCall
-          .navigateWithDirectoryTree(
-              appId, `/team_drives/${teamDrive}`, 'Team Drives', 'drive')
-          .then(this.next);
+          null, RootPath.DRIVE, this.next, [], BASIC_DRIVE_ENTRY_SET);
     },
     // Select the given |path|.
-    function() {
+    function(results) {
+      appId = results.windowId;
       remoteCall.callRemoteTestUtil('selectFile', appId, [path], this.next);
     },
     // Wait for the entry to be selected.
@@ -194,15 +168,6 @@
 };
 
 /**
- * Tests sharing a hosted file (gdoc) on Drive.
- */
-testcase.shareHostedFileDrive = function() {
-  const URL =
-      'https://document_alternate_link/Test%20Document?userstoinvite=%22%22';
-  shareWithOthersExpectBrowserURL('Test Document.gdoc', URL);
-};
-
-/**
  * Tests managing a file on Drive.
  */
 testcase.manageFileDrive = function() {
@@ -226,103 +191,4 @@
   manageWithDriveExpectBrowserURL('Test Document.gdoc', URL);
 };
 
-/**
- * Tests sharing a file in a team drive.
- */
-testcase.shareFileTeamDrive = function() {
-  const URL =
-      'https://file_alternate_link/teamDriveAFile.txt?userstoinvite=%22%22';
-  shareWithOthersExpectBrowserURL('teamDriveAFile.txt', URL, 'Team Drive A');
-};
-
-/**
- * Tests that sharing a directory in a team drive is not allowed.
- */
-testcase.shareDirectoryTeamDrive = function() {
-  let appId;
-  const teamDrive = 'Team Drive A';
-  const path = 'teamDriveADirectory';
-
-  StepsRunner.run([
-    // Open Files app on Drive.
-    function() {
-      setupAndWaitUntilReady(
-          null, RootPath.DRIVE, this.next, [],
-          BASIC_DRIVE_ENTRY_SET.concat(TEAM_DRIVE_ENTRY_SET));
-    },
-    // Navigate to the team drive.
-    function(results) {
-      appId = results.windowId;
-      remoteCall
-          .navigateWithDirectoryTree(
-              appId, `/team_drives/${teamDrive}`, 'Team Drives', 'drive')
-          .then(this.next);
-    },
-    // Select the given |path|.
-    function() {
-      remoteCall.callRemoteTestUtil('selectFile', appId, [path], this.next);
-    },
-    // Wait for the entry to be selected.
-    function(result) {
-      chrome.test.assertTrue(!!result, 'selectFile failed');
-      remoteCall.waitForElement(appId, '.table-row[selected]').then(this.next);
-    },
-    // Right-click the selected entry.
-    function(result) {
-      chrome.test.assertTrue(!!result);
-      remoteCall.callRemoteTestUtil(
-          'fakeMouseRightClick', appId, ['.table-row[selected]'], this.next);
-    },
-    // Wait for the context menu to appear.
-    function(result) {
-      chrome.test.assertTrue(!!result, 'fakeMouseClick failed');
-      remoteCall.waitForElement(appId, '#file-context-menu:not([hidden])')
-          .then(this.next);
-    },
-    // Wait for the "Share" menu item to appear.
-    function(result) {
-      chrome.test.assertTrue(!!result);
-      remoteCall
-          .waitForElement(appId, '[command="#share"]:not([hidden])[disabled]')
-          .then(this.next);
-    },
-    function() {
-      checkIfNoErrorsOccured(this.next);
-    }
-  ]);
-};
-
-/**
- * Tests sharing a hosted file (gdoc) in a team drive.
- */
-testcase.shareHostedFileTeamDrive = function() {
-  const URL =
-      'https://document_alternate_link/teamDriveAHostedDoc?userstoinvite=%22%22';
-  shareWithOthersExpectBrowserURL(
-      'teamDriveAHostedDoc.gdoc', URL, 'Team Drive A');
-};
-
-/**
- * Tests managing a file in a team drive.
- */
-testcase.manageFileTeamDrive = function() {
-  const URL = 'https://file_alternate_link/teamDriveAFile.txt';
-  manageWithDriveExpectBrowserURL('teamDriveAFile.txt', URL, 'Team Drive A');
-};
-
-/**
- * Tests managing a directory in a team drive.
- */
-testcase.manageDirectoryTeamDrive = function() {
-  const URL = 'https://folder_alternate_link/teamDriveADirectory';
-  manageWithDriveExpectBrowserURL('teamDriveADirectory', URL, 'Team Drive A');
-};
-
-/**
- * Tests managing a hosted file (gdoc) in a team drive.
- */
-testcase.manageHostedFileTeamDrive = function() {
-  const URL = 'https://document_alternate_link/teamDriveAHostedDoc';
-  manageWithDriveExpectBrowserURL(
-      'teamDriveAHostedDoc.gdoc', URL, 'Team Drive A');
-};
+// TODO(903637): Add tests for sharing a file on Team Drives.
diff --git a/ui/file_manager/integration_tests/test_util.js b/ui/file_manager/integration_tests/test_util.js
index 806bb8c..3e4a459 100644
--- a/ui/file_manager/integration_tests/test_util.js
+++ b/ui/file_manager/integration_tests/test_util.js
@@ -758,23 +758,6 @@
     },
   }),
 
-  teamDriveADirectory: new TestEntryInfo({
-    type: EntryType.DIRECTORY,
-    targetPath: 'teamDriveADirectory',
-    lastModifiedTime: 'Jan 1, 2000, 1:00 AM',
-    nameText: 'teamDriveADirectory',
-    sizeText: '--',
-    typeText: 'Folder',
-    teamDriveName: 'Team Drive A',
-    capabilities: {
-      canCopy: true,
-      canDelete: true,
-      canRename: true,
-      canAddChildren: true,
-      canShare: false,
-    },
-  }),
-
   teamDriveAHostedFile: new TestEntryInfo({
     type: EntryType.FILE,
     targetPath: 'teamDriveAHostedDoc',
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index b0f4756..b27ea80 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -1123,10 +1123,9 @@
     if (!this_ref)
       return ui::POST_DISPATCH_NONE;
 
-    // Do not check mnemonics if the Alt, Ctrl, or Cmd modifiers are pressed.
-    // For example Ctrl+<T> is an accelerator, but <T> only is a mnemonic.
-    const int kKeyFlagsMask =
-        ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN;
+    // Do not check mnemonics if the Alt or Ctrl modifiers are pressed. For
+    // example Ctrl+<T> is an accelerator, but <T> only is a mnemonic.
+    const int kKeyFlagsMask = ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN;
     const int flags = event->flags();
     if (exit_type() == EXIT_NONE && (flags & kKeyFlagsMask) == 0) {
       base::char16 c = event->GetCharacter();