diff --git a/.gn b/.gn
index 17bf869..e29a1249 100644
--- a/.gn
+++ b/.gn
@@ -91,7 +91,6 @@
   "//chrome/services/qrcode_generator:*",  # 1 error
   "//chrome/services/removable_storage_writer:*",  # 1 error
   "//chrome/services/sharing/public/cpp:*",  # 2 errors
-  "//chrome/services/sharing:*",  # 1 error
   "//chrome/services/speech:*",  # 5 errors
   "//chrome/services/util_win:*",  # 1 error
   "//chrome/test/chromedriver:*",  # 115 errors
diff --git a/DEPS b/DEPS
index ba22a36d..f620cd0 100644
--- a/DEPS
+++ b/DEPS
@@ -195,11 +195,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': '68e5f29d849a36edd9e9243dc05b88e4b288dd9b',
+  'skia_revision': 'c1eb58de32c016eb60e7a46046321ffe351e8222',
   # 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': 'df4466baeaf037b9985c5f82f56aa9e1788e4600',
+  'v8_revision': 'df76b72ef7394d85badaacaecf6e1a0beb986db7',
   # 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.
@@ -207,15 +207,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'cd5489ad46bd1a3f9e80073a8cb1760ed8b17f96',
+  'angle_revision': '0dd63428948f70f03566665007819d326f937b72',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '97f9923235cf5a24d8ce49f93bd22429d2a68548',
+  'swiftshader_revision': 'c5d08140dbebcdb01cd8debc7fcc2647599d0bb3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '9a3f345ba7c49cdc78e8caf4e667d94da8fcbbd9',
+  'pdfium_revision': '75efd91227ebf7cfbaffc82935e27632b0c40ea5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -266,7 +266,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '270e6f332c4179801c60551c828c07c69104e594',
+  'devtools_frontend_revision': '62ab4833a6a13ab1c863fa8a2682afea87447c77',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -302,7 +302,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '717e7877cac15d393fd3bb1bd872679de8b59add',
+  'spv_tools_revision': 'a3b0adc306c5e7df43ecfd56d8f41b6b7e39ca18',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -545,7 +545,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '0a0f7347fac7639ac132934705e88f69d7fedc6b',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '3132beea793356e3b0f6cb77c32c9c5a1a23e68b',
       'condition': 'checkout_ios',
   },
 
@@ -946,7 +946,7 @@
     Var('chromium_git') + '/codecs/libgav1.git' + '@' + 'e46493b9148e0d1e63f55b5890bff503822616e5',
 
   'src/third_party/glslang/src':
-    Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '9eef54b2513ca6b40b47b07d24f453848b65c0df',
+    Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + 'b99a6a7273181deeb08859c0fdb0c77c7e8a4500',
 
   'src/third_party/google_toolbox_for_mac/src': {
       'url': Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'),
@@ -1326,7 +1326,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': '53Ps2Qo0mizBNjRI9qS90a_RTYhxglcY6H9yccc0ckcC'
+              'version': 'dOv-cP7Iqrr9QqppeGdHqAO3EEhTVVBb_hVADr88ZJQC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1476,7 +1476,7 @@
   },
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '539e8783de6228a56ec3ea5d84ce348082352210',
+    Var('webrtc_git') + '/src.git' + '@' + '0bc68bd1648454f5ac2987cdf2014b71d1a80e07',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1548,7 +1548,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f9491204a8a8d6e82c4c6efc53a982dc6e1aafb9',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@86079a48c1576f04239c4de46a1efcdd86d858d0',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index ebcb96a..daf0366 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -360,6 +360,11 @@
     "//android_webview/nonembedded:nonembedded_java",
     "//android_webview/support_library:support_lib_glue_java",
   ]
+
+  # If the R SDK isn't public yet, include the downstream code to support R.
+  if (!public_android_sdk && android_sdk_release == "r") {
+    deps += [ "//clank/android_webview/next:r_sdk_java" ]
+  }
 }
 
 # Contains all Java dependencies used by WebView.
diff --git a/android_webview/browser/gfx/output_surface_provider_webview.cc b/android_webview/browser/gfx/output_surface_provider_webview.cc
index b867948..6d0a268 100644
--- a/android_webview/browser/gfx/output_surface_provider_webview.cc
+++ b/android_webview/browser/gfx/output_surface_provider_webview.cc
@@ -28,7 +28,7 @@
 
 namespace {
 
-void OnContextLost() {
+void OnContextLost(bool synthetic_loss) {
   NOTREACHED() << "Non owned context lost!";
 }
 
diff --git a/android_webview/system_webview_apk_tmpl.gni b/android_webview/system_webview_apk_tmpl.gni
index 33e7fe36..4d556b3d 100644
--- a/android_webview/system_webview_apk_tmpl.gni
+++ b/android_webview/system_webview_apk_tmpl.gni
@@ -48,11 +48,6 @@
       "//android_webview:pak_file_assets",
     ]
 
-    # If the R SDK isn't public yet, include the downstream code to support R.
-    if (!public_android_sdk && android_sdk_release == "r") {
-      deps += [ "//clank/android_webview/next:r_sdk_java" ]
-    }
-
     if (_exclude_weblayer_java) {
       deps += [ "//android_webview:android_webview_no_weblayer_java" ]
     } else {
diff --git a/base/files/file_enumerator.h b/base/files/file_enumerator.h
index b2bd5ab..9554f2a 100644
--- a/base/files/file_enumerator.h
+++ b/base/files/file_enumerator.h
@@ -57,6 +57,8 @@
     FilePath GetName() const;
 
     int64_t GetSize() const;
+
+    // On POSIX systems, this is rounded down to the second.
     Time GetLastModifiedTime() const;
 
 #if defined(OS_WIN)
diff --git a/base/files/file_enumerator_unittest.cc b/base/files/file_enumerator_unittest.cc
index ccd15113..362d4bf 100644
--- a/base/files/file_enumerator_unittest.cc
+++ b/base/files/file_enumerator_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "base/files/file_enumerator.h"
 
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -11,6 +12,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
 #include "build/build_config.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -28,6 +30,57 @@
     FileEnumerator::FolderSearchPolicy::MATCH_ONLY,
     FileEnumerator::FolderSearchPolicy::ALL};
 
+struct TestFile {
+  TestFile(const FilePath::CharType* file_name, const char* c)
+      : path(file_name), contents(c) {}
+
+  TestFile(const FilePath::CharType* directory,
+           const FilePath::CharType* file_name,
+           const char* c)
+      : path(FilePath(directory).Append(file_name)), contents(c) {}
+
+  const FilePath path;
+  const std::string contents;
+  File::Info info;
+  bool found = false;
+};
+
+struct TestDirectory {
+  explicit TestDirectory(const FilePath::CharType* n) : name(n) {}
+  const FilePath name;
+  File::Info info;
+  bool found = false;
+};
+
+void CheckModificationTime(const FileEnumerator::FileInfo& actual,
+                           Time expected_last_modified_time) {
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+  // On POSIX, GetLastModifiedTime() rounds down to the second, but
+  // File::GetInfo() does not.
+  Time::Exploded exploded;
+  expected_last_modified_time.UTCExplode(&exploded);
+  exploded.millisecond = 0;
+  EXPECT_TRUE(Time::FromUTCExploded(exploded, &expected_last_modified_time));
+#endif
+  EXPECT_EQ(actual.GetLastModifiedTime(), expected_last_modified_time);
+}
+
+void CheckFileAgainstInfo(const FileEnumerator::FileInfo& actual,
+                          TestFile& expected) {
+  EXPECT_FALSE(expected.found)
+      << "Got " << expected.path.BaseName().value() << " twice";
+  expected.found = true;
+  EXPECT_EQ(actual.GetSize(), int64_t(expected.contents.size()));
+  CheckModificationTime(actual, expected.info.last_modified);
+}
+
+void CheckDirectoryAgainstInfo(const FileEnumerator::FileInfo& actual,
+                               TestDirectory& expected) {
+  EXPECT_FALSE(expected.found) << "Got " << expected.name.value() << " twice";
+  expected.found = true;
+  CheckModificationTime(actual, expected.info.last_modified);
+}
+
 circular_deque<FilePath> RunEnumerator(
     const FilePath& root_path,
     bool recursive,
@@ -47,6 +100,34 @@
   return WriteFile(path, "42", sizeof("42")) == sizeof("42");
 }
 
+bool GetFileInfo(const FilePath& file_path, File::Info& info) {
+  // FLAG_BACKUP_SEMANTICS: Needed to open directories on Windows.
+  File f(file_path,
+         File::FLAG_OPEN | File::FLAG_READ | File::FLAG_BACKUP_SEMANTICS);
+  if (!f.IsValid()) {
+    LOG(ERROR) << "Could not open " << file_path.value() << ": "
+               << File::ErrorToString(f.error_details());
+    return false;
+  }
+  if (!f.GetInfo(&info)) {
+    std::string last_error = File::ErrorToString(File::GetLastFileError());
+    LOG(ERROR) << "Could not get info about " << file_path.value() << ": "
+               << last_error;
+    return false;
+  }
+
+  return true;
+}
+
+void SetUpTestFiles(const ScopedTempDir& temp_dir,
+                    std::vector<TestFile>& files) {
+  for (TestFile& file : files) {
+    const FilePath file_path = temp_dir.GetPath().Append(file.path);
+    ASSERT_TRUE(WriteFile(file_path, file.contents));
+    ASSERT_TRUE(GetFileInfo(file_path, file.info));
+  }
+}
+
 }  // namespace
 
 TEST(FileEnumerator, NotExistingPath) {
@@ -365,4 +446,163 @@
 }
 #endif
 
+// Test FileEnumerator::GetInfo() on some files and ensure all the returned
+// information is correct.
+TEST(FileEnumerator, GetInfo) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  std::vector<TestFile> files = {
+      TestFile(FILE_PATH_LITERAL("file1"), "First"),
+      TestFile(FILE_PATH_LITERAL("file2"), "Second"),
+      TestFile(FILE_PATH_LITERAL("file3"), "Third-third-third")};
+  SetUpTestFiles(temp_dir, files);
+
+  FileEnumerator file_enumerator(temp_dir.GetPath(), false,
+                                 FileEnumerator::FILES);
+  while (!file_enumerator.Next().empty()) {
+    auto info = file_enumerator.GetInfo();
+    bool found = false;
+    for (TestFile& file : files) {
+      if (info.GetName() == file.path.BaseName()) {
+        CheckFileAgainstInfo(info, file);
+        found = true;
+        break;
+      }
+    }
+
+    EXPECT_TRUE(found) << "Got unexpected result " << info.GetName().value();
+  }
+
+  for (const TestFile& file : files) {
+    EXPECT_TRUE(file.found)
+        << "File " << file.path.value() << " was not returned";
+  }
+}
+
+// Test that FileEnumerator::GetInfo() works when searching recursively. It also
+// tests that it returns the correct information about directories.
+TEST(FileEnumerator, GetInfoRecursive) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  TestDirectory directories[] = {TestDirectory(FILE_PATH_LITERAL("dir1")),
+                                 TestDirectory(FILE_PATH_LITERAL("dir2")),
+                                 TestDirectory(FILE_PATH_LITERAL("dir3")),
+                                 TestDirectory(FILE_PATH_LITERAL("dirempty"))};
+
+  for (const TestDirectory& dir : directories) {
+    const FilePath dir_path = temp_dir.GetPath().Append(dir.name);
+    ASSERT_TRUE(CreateDirectory(dir_path));
+  }
+
+  std::vector<TestFile> files = {
+      TestFile(FILE_PATH_LITERAL("dir1"), FILE_PATH_LITERAL("file1"), "First"),
+      TestFile(FILE_PATH_LITERAL("dir1"), FILE_PATH_LITERAL("file2"), "Second"),
+      TestFile(FILE_PATH_LITERAL("dir2"), FILE_PATH_LITERAL("fileA"),
+               "Third-third-3"),
+      TestFile(FILE_PATH_LITERAL("dir3"), FILE_PATH_LITERAL(".file"), "Dot")};
+  SetUpTestFiles(temp_dir, files);
+
+  // Get last-modification times for directories. Must be done after we create
+  // all the files.
+  for (TestDirectory& dir : directories) {
+    const FilePath dir_path = temp_dir.GetPath().Append(dir.name);
+    ASSERT_TRUE(GetFileInfo(dir_path, dir.info));
+  }
+
+  FileEnumerator file_enumerator(
+      temp_dir.GetPath(), true,
+      FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
+  while (!file_enumerator.Next().empty()) {
+    auto info = file_enumerator.GetInfo();
+    bool found = false;
+    if (info.IsDirectory()) {
+      for (TestDirectory& dir : directories) {
+        if (info.GetName() == dir.name) {
+          CheckDirectoryAgainstInfo(info, dir);
+          found = true;
+          break;
+        }
+      }
+    } else {
+      for (TestFile& file : files) {
+        if (info.GetName() == file.path.BaseName()) {
+          CheckFileAgainstInfo(info, file);
+          found = true;
+          break;
+        }
+      }
+    }
+
+    EXPECT_TRUE(found) << "Got unexpected result " << info.GetName().value();
+  }
+
+  for (const TestDirectory& dir : directories) {
+    EXPECT_TRUE(dir.found) << "Directory " << dir.name.value()
+                           << " was not returned";
+  }
+  for (const TestFile& file : files) {
+    EXPECT_TRUE(file.found)
+        << "File " << file.path.value() << " was not returned";
+  }
+}
+
+#if defined(OS_FUCHSIA)
+// FileEnumerator::GetInfo does not work correctly with INCLUDE_DOT_DOT.
+// https://crbug.com/1106172
+#else
+// Tests that FileEnumerator::GetInfo() returns the correct info for the ..
+// directory.
+TEST(FileEnumerator, GetInfoDotDot) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  const FilePath::CharType kSubdir[] = FILE_PATH_LITERAL("subdir");
+  const FilePath subdir_path = temp_dir.GetPath().Append(kSubdir);
+  ASSERT_TRUE(CreateDirectory(subdir_path));
+
+  std::vector<TestFile> files = {
+      TestFile(kSubdir, FILE_PATH_LITERAL("file1"), "First"),
+      TestFile(kSubdir, FILE_PATH_LITERAL("file2"), "Second"),
+      TestFile(kSubdir, FILE_PATH_LITERAL("file3"), "Third-third-third")};
+  SetUpTestFiles(temp_dir, files);
+
+  TestDirectory dotdot(FILE_PATH_LITERAL(".."));
+  // test_dir/subdir/.. is just test_dir.
+  ASSERT_TRUE(GetFileInfo(temp_dir.GetPath(), dotdot.info));
+
+  FileEnumerator file_enumerator(subdir_path, false,
+                                 FileEnumerator::FILES |
+                                     FileEnumerator::DIRECTORIES |
+                                     FileEnumerator::INCLUDE_DOT_DOT);
+  while (!file_enumerator.Next().empty()) {
+    auto info = file_enumerator.GetInfo();
+    bool found = false;
+    if (info.IsDirectory()) {
+      EXPECT_EQ(info.GetName(), FilePath(FILE_PATH_LITERAL("..")));
+      CheckDirectoryAgainstInfo(info, dotdot);
+      found = true;
+    } else {
+      for (TestFile& file : files) {
+        if (info.GetName() == file.path.BaseName()) {
+          CheckFileAgainstInfo(info, file);
+          found = true;
+          break;
+        }
+      }
+    }
+
+    EXPECT_TRUE(found) << "Got unexpected result " << info.GetName().value();
+  }
+
+  EXPECT_TRUE(dotdot.found) << "Directory .. was not returned";
+
+  for (const TestFile& file : files) {
+    EXPECT_TRUE(file.found)
+        << "File " << file.path.value() << " was not returned";
+  }
+}
+#endif  // !defined(OS_FUCHSIA)
+
 }  // namespace base
diff --git a/base/location.h b/base/location.h
index c9057b2..a5d3a92 100644
--- a/base/location.h
+++ b/base/location.h
@@ -18,7 +18,7 @@
 
 namespace base {
 
-#if defined(__has_builtin)
+#if defined(__clang__)
 // Clang allows detection of these builtins.
 #define SUPPORTS_LOCATION_BUILTINS                                       \
   (__has_builtin(__builtin_FUNCTION) && __has_builtin(__builtin_FILE) && \
diff --git a/base/memory/checked_ptr.h b/base/memory/checked_ptr.h
index 46f0c4ba..6fc02d1f 100644
--- a/base/memory/checked_ptr.h
+++ b/base/memory/checked_ptr.h
@@ -343,15 +343,6 @@
 
 #endif  // defined(ARCH_CPU_64_BITS) && !defined(OS_NACL)
 
-template <typename T>
-struct DereferencedPointerType {
-  using Type = decltype(*std::declval<T*>());
-};
-// This explicitly doesn't define any type aliases, since dereferencing void is
-// invalid.
-template <>
-struct DereferencedPointerType<void> {};
-
 }  // namespace internal
 
 // DO NOT USE! EXPERIMENTAL ONLY! This is helpful for local testing!
@@ -423,11 +414,10 @@
     return wrapped_ptr_ != Impl::GetWrappedNullPtr();
   }
 
-  // Use SFINAE to avoid defining |operator*| for T=void, which wouldn't compile
-  // due to |void&|.
   template <typename U = T,
-            typename V = typename internal::DereferencedPointerType<U>::Type>
-  ALWAYS_INLINE V& operator*() const {
+            typename Unused = std::enable_if_t<
+                !std::is_void<typename std::remove_cv<U>::type>::value>>
+  ALWAYS_INLINE U& operator*() const {
     return *GetForDereference();
   }
   ALWAYS_INLINE T* operator->() const { return GetForDereference(); }
diff --git a/base/memory/checked_ptr_unittest.nc b/base/memory/checked_ptr_unittest.nc
index c19b4779..f0e37de4 100644
--- a/base/memory/checked_ptr_unittest.nc
+++ b/base/memory/checked_ptr_unittest.nc
@@ -73,7 +73,7 @@
   std::ignore = static_cast<Unrelated*>(ptr);
 }
 
-#elif defined(NCTEST_VOID_DEREFERENCE) // [r"ISO C\+\+ does not allow indirection on operand of type 'const void \*' \[-Wvoid-ptr-dereference\]"]
+#elif defined(NCTEST_VOID_DEREFERENCE) // [r"indirection requires pointer operand \('CheckedPtr<const void>' invalid\)"]
 
 void WontCompile() {
   const char foo[] = "42";
diff --git a/base/util/ranges/algorithm.h b/base/util/ranges/algorithm.h
index 48e3e15..2c95a02 100644
--- a/base/util/ranges/algorithm.h
+++ b/base/util/ranges/algorithm.h
@@ -2222,17 +2222,227 @@
 // [alg.reverse] Reverse
 // Reference: https://wg21.link/alg.reverse
 
-// TODO(crbug.com/1071094): Implement.
+// Effects: For each non-negative integer `i < (last - first) / 2`, applies
+// `std::iter_swap` to all pairs of iterators `first + i, (last - i) - 1`.
+//
+// Returns: `last`.
+//
+// Complexity: Exactly `(last - first)/2` swaps.
+//
+// Reference: https://wg21.link/alg.reverse#:~:text=ranges::reverse(I
+template <typename BidirectionalIterator,
+          typename = internal::iterator_category_t<BidirectionalIterator>>
+constexpr auto reverse(BidirectionalIterator first,
+                       BidirectionalIterator last) {
+  std::reverse(first, last);
+  return last;
+}
+
+// Effects: For each non-negative integer `i < size(range) / 2`, applies
+// `std::iter_swap` to all pairs of iterators
+// `begin(range) + i, (end(range) - i) - 1`.
+//
+// Returns: `end(range)`.
+//
+// Complexity: Exactly `size(range)/2` swaps.
+//
+// Reference: https://wg21.link/alg.reverse#:~:text=ranges::reverse(R
+template <typename Range, typename = internal::range_category_t<Range>>
+constexpr auto reverse(Range&& range) {
+  return ranges::reverse(ranges::begin(range), ranges::end(range));
+}
+
+// Let `N` be `last - first`.
+//
+// Preconditions: The ranges `[first, last)` and `[result, result + N)` do not
+// overlap.
+//
+// Effects: Copies the range `[first, last)` to the range `[result, result + N)`
+// such that for every non-negative integer `i < N` the following assignment
+// takes place: `*(result + N - 1 - i) = *(first + i)`.
+//
+// Returns: `result + N`.
+//
+// Complexity: Exactly `N` assignments.
+//
+// Reference: https://wg21.link/alg.reverse#:~:text=ranges::reverse_copy(I
+template <typename BidirectionalIterator,
+          typename OutputIterator,
+          typename = internal::iterator_category_t<BidirectionalIterator>,
+          typename = internal::iterator_category_t<OutputIterator>>
+constexpr auto reverse_copy(BidirectionalIterator first,
+                            BidirectionalIterator last,
+                            OutputIterator result) {
+  return std::reverse_copy(first, last, result);
+}
+
+// Let `N` be `size(range)`.
+//
+// Preconditions: The ranges `range` and `[result, result + N)` do not
+// overlap.
+//
+// Effects: Copies `range` to the range `[result, result + N)` such that for
+// every non-negative integer `i < N` the following assignment takes place:
+// `*(result + N - 1 - i) = *(begin(range) + i)`.
+//
+// Returns: `result + N`.
+//
+// Complexity: Exactly `N` assignments.
+//
+// Reference: https://wg21.link/alg.reverse#:~:text=ranges::reverse_copy(R
+template <typename Range,
+          typename OutputIterator,
+          typename = internal::range_category_t<Range>,
+          typename = internal::iterator_category_t<OutputIterator>>
+constexpr auto reverse_copy(Range&& range, OutputIterator result) {
+  return ranges::reverse_copy(ranges::begin(range), ranges::end(range), result);
+}
 
 // [alg.rotate] Rotate
 // Reference: https://wg21.link/alg.rotate
 
-// TODO(crbug.com/1071094): Implement.
+// Preconditions: `[first, middle)` and `[middle, last)` are valid ranges.
+//
+// Effects: For each non-negative integer `i < (last - first)`, places the
+// element from the position `first + i` into position
+// `first + (i + (last - middle)) % (last - first)`.
+//
+// Returns: `first + (last - middle)`.
+//
+// Complexity: At most `last - first` swaps.
+//
+// Reference: https://wg21.link/alg.rotate#:~:text=ranges::rotate(I
+template <typename ForwardIterator,
+          typename = internal::iterator_category_t<ForwardIterator>>
+constexpr auto rotate(ForwardIterator first,
+                      ForwardIterator middle,
+                      ForwardIterator last) {
+  return std::rotate(first, middle, last);
+}
+
+// Preconditions: `[begin(range), middle)` and `[middle, end(range))` are valid
+// ranges.
+//
+// Effects: For each non-negative integer `i < size(range)`, places the element
+// from the position `begin(range) + i` into position
+// `begin(range) + (i + (end(range) - middle)) % size(range)`.
+//
+// Returns: `begin(range) + (end(range) - middle)`.
+//
+// Complexity: At most `size(range)` swaps.
+//
+// Reference: https://wg21.link/alg.rotate#:~:text=ranges::rotate(R
+template <typename Range, typename = internal::range_category_t<Range>>
+constexpr auto rotate(Range&& range, iterator_t<Range> middle) {
+  return ranges::rotate(ranges::begin(range), middle, ranges::end(range));
+}
+
+// Let `N` be `last - first`.
+//
+// Preconditions: `[first, middle)` and `[middle, last)` are valid ranges. The
+// ranges `[first, last)` and `[result, result + N)` do not overlap.
+//
+// Effects: Copies the range `[first, last)` to the range `[result, result + N)`
+// such that for each non-negative integer `i < N` the following assignment
+// takes place: `*(result + i) = *(first + (i + (middle - first)) % N)`.
+//
+// Returns: `result + N`.
+//
+// Complexity: Exactly `N` assignments.
+//
+// Reference: https://wg21.link/alg.rotate#:~:text=ranges::rotate_copy(I
+template <typename ForwardIterator,
+          typename OutputIterator,
+          typename = internal::iterator_category_t<ForwardIterator>,
+          typename = internal::iterator_category_t<OutputIterator>>
+constexpr auto rotate_copy(ForwardIterator first,
+                           ForwardIterator middle,
+                           ForwardIterator last,
+                           OutputIterator result) {
+  return std::rotate_copy(first, middle, last, result);
+}
+
+// Let `N` be `size(range)`.
+//
+// Preconditions: `[begin(range), middle)` and `[middle, end(range))` are valid
+// ranges. The ranges `range` and `[result, result + N)` do not overlap.
+//
+// Effects: Copies `range` to the range `[result, result + N)` such that for
+// each non-negative integer `i < N` the following assignment takes place:
+// `*(result + i) = *(begin(range) + (i + (middle - begin(range))) % N)`.
+//
+// Returns: `result + N`.
+//
+// Complexity: Exactly `N` assignments.
+//
+// Reference: https://wg21.link/alg.rotate#:~:text=ranges::rotate_copy(R
+template <typename Range,
+          typename OutputIterator,
+          typename = internal::range_category_t<Range>,
+          typename = internal::iterator_category_t<OutputIterator>>
+constexpr auto rotate_copy(Range&& range,
+                           iterator_t<Range> middle,
+                           OutputIterator result) {
+  return ranges::rotate_copy(ranges::begin(range), middle, ranges::end(range),
+                             result);
+}
+
+// [alg.random.sample] Sample
+// Reference: https://wg21.link/alg.random.sample
+
+// Currently not implemented due to lack of std::sample in C++14.
+// TODO(crbug.com/1071094): Consider implementing a hand-rolled version.
 
 // [alg.random.shuffle] Shuffle
 // Reference: https://wg21.link/alg.random.shuffle
 
-// TODO(crbug.com/1071094): Implement.
+// Preconditions: The type `std::remove_reference_t<UniformRandomBitGenerator>`
+// meets the uniform random bit generator requirements.
+//
+// Effects: Permutes the elements in the range `[first, last)` such that each
+// possible permutation of those elements has equal probability of appearance.
+//
+// Returns: `last`.
+//
+// Complexity: Exactly `(last - first) - 1` swaps.
+//
+// Remarks: To the extent that the implementation of this function makes use of
+// random numbers, the object referenced by g shall serve as the
+// implementation's source of randomness.
+//
+// Reference: https://wg21.link/alg.random.shuffle#:~:text=ranges::shuffle(I
+template <typename RandomAccessIterator,
+          typename UniformRandomBitGenerator,
+          typename = internal::iterator_category_t<RandomAccessIterator>>
+constexpr auto shuffle(RandomAccessIterator first,
+                       RandomAccessIterator last,
+                       UniformRandomBitGenerator&& g) {
+  std::shuffle(first, last, std::forward<UniformRandomBitGenerator>(g));
+  return last;
+}
+
+// Preconditions: The type `std::remove_reference_t<UniformRandomBitGenerator>`
+// meets the uniform random bit generator requirements.
+//
+// Effects: Permutes the elements in `range` such that each possible permutation
+// of those elements has equal probability of appearance.
+//
+// Returns: `end(range)`.
+//
+// Complexity: Exactly `size(range) - 1` swaps.
+//
+// Remarks: To the extent that the implementation of this function makes use of
+// random numbers, the object referenced by g shall serve as the
+// implementation's source of randomness.
+//
+// Reference: https://wg21.link/alg.random.shuffle#:~:text=ranges::shuffle(R
+template <typename Range,
+          typename UniformRandomBitGenerator,
+          typename = internal::range_category_t<Range>>
+constexpr auto shuffle(Range&& range, UniformRandomBitGenerator&& g) {
+  return ranges::shuffle(ranges::begin(range), ranges::end(range),
+                         std::forward<UniformRandomBitGenerator>(g));
+}
 
 // [alg.nonmodifying] Sorting and related operations
 // Reference: https://wg21.link/alg.sorting
diff --git a/base/util/ranges/algorithm_unittest.cc b/base/util/ranges/algorithm_unittest.cc
index 67af53c6..e018502 100644
--- a/base/util/ranges/algorithm_unittest.cc
+++ b/base/util/ranges/algorithm_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 #include <functional>
+#include <random>
 #include <utility>
 
 #include "base/util/ranges/functional.h"
@@ -672,6 +673,69 @@
   EXPECT_THAT(output, ElementsAre(0, 1, 2, 0, 0));
 }
 
+TEST(RangesTest, Reverse) {
+  int input[] = {0, 1, 2, 3, 4};
+
+  EXPECT_EQ(input + 4, ranges::reverse(input + 2, input + 4));
+  EXPECT_THAT(input, ElementsAre(0, 1, 3, 2, 4));
+
+  EXPECT_EQ(input + 5, ranges::reverse(input));
+  EXPECT_THAT(input, ElementsAre(4, 2, 3, 1, 0));
+}
+
+TEST(RangesTest, ReverseCopy) {
+  int input[] = {0, 1, 2, 3, 4};
+  int output[] = {0, 0, 0, 0, 0};
+
+  EXPECT_EQ(output + 2, ranges::reverse_copy(input + 2, input + 4, output));
+  EXPECT_THAT(input, ElementsAre(0, 1, 2, 3, 4));
+  EXPECT_THAT(output, ElementsAre(3, 2, 0, 0, 0));
+
+  EXPECT_EQ(output + 5, ranges::reverse_copy(input, output));
+  EXPECT_THAT(input, ElementsAre(0, 1, 2, 3, 4));
+  EXPECT_THAT(output, ElementsAre(4, 3, 2, 1, 0));
+}
+
+TEST(RangesTest, Rotate) {
+  int input[] = {0, 1, 2, 3, 4};
+
+  EXPECT_EQ(input + 3, ranges::rotate(input + 2, input + 3, input + 4));
+  EXPECT_THAT(input, ElementsAre(0, 1, 3, 2, 4));
+
+  EXPECT_EQ(input + 3, ranges::rotate(input, input + 2));
+  EXPECT_THAT(input, ElementsAre(3, 2, 4, 0, 1));
+}
+
+TEST(RangesTest, RotateCopy) {
+  int input[] = {0, 1, 2, 3, 4};
+  int output[] = {0, 0, 0, 0, 0};
+
+  EXPECT_EQ(output + 2,
+            ranges::rotate_copy(input + 2, input + 3, input + 4, output));
+  EXPECT_THAT(input, ElementsAre(0, 1, 2, 3, 4));
+  EXPECT_THAT(output, ElementsAre(3, 2, 0, 0, 0));
+
+  EXPECT_EQ(output + 5, ranges::rotate_copy(input, input + 3, output));
+  EXPECT_THAT(input, ElementsAre(0, 1, 2, 3, 4));
+  EXPECT_THAT(output, ElementsAre(3, 4, 0, 1, 2));
+}
+
+TEST(RangesTest, Shuffle) {
+  int input[] = {0, 1, 2, 3, 4};
+
+  // Shuffles input[2] and input[3], thus we can't be certain about their
+  // positions.
+  EXPECT_EQ(input + 4, ranges::shuffle(input + 2, input + 4,
+                                       std::default_random_engine()));
+  EXPECT_EQ(input[0], 0);
+  EXPECT_EQ(input[1], 1);
+  EXPECT_EQ(input[4], 4);
+  EXPECT_THAT(input, ::testing::UnorderedElementsAre(0, 1, 2, 3, 4));
+
+  EXPECT_EQ(input + 5, ranges::shuffle(input, std::default_random_engine()));
+  EXPECT_THAT(input, ::testing::UnorderedElementsAre(0, 1, 2, 3, 4));
+}
+
 TEST(RangesTest, LowerBound) {
   int array[] = {0, 0, 1, 1, 2, 2};
 
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 9357ea1..7feab25 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20200720.3.1
+0.20200721.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 9357ea1..7feab25 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20200720.3.1
+0.20200721.1.1
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
index 054bd6a..a0191d0e 100644
--- a/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -7,6 +7,8 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_timeouts.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "cc/layers/effect_tree_layer_list_iterator.h"
@@ -39,11 +41,6 @@
           ::testing::tuple<TestRendererType, CompositorMode>> {
  public:
   LayerTreeHostCopyRequestTest() : LayerTreeTest(renderer_type()) {}
-  ~LayerTreeHostCopyRequestTest() {
-    // To prevent any tasks posted from previous tests from interfering wait for
-    // the task environment to empty.
-    CCTestSuite::RunUntilIdle();
-  }
 
   TestRendererType renderer_type() const {
     return ::testing::get<0>(GetParam());
@@ -231,9 +228,7 @@
     client_.set_bounds(root_->bounds());
   }
 
-  void BeginTest() override {
-    PostSetNeedsCommitToMainThread();
-  }
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
   void DidCommit() override {
     int frame = layer_tree_host()->SourceFrameNumber();
@@ -294,10 +289,7 @@
     client_.set_bounds(root_->bounds());
   }
 
-  void BeginTest() override {
-    callback_count_ = 0;
-    PostSetNeedsCommitToMainThread();
-  }
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
   void DidCommit() override {
     int frame = layer_tree_host()->SourceFrameNumber();
@@ -308,68 +300,69 @@
             viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP,
             base::BindOnce(
                 &LayerTreeHostCopyRequestTestLayerDestroyed::CopyOutputCallback,
-                base::Unretained(this))));
+                base::Unretained(this), &main_destroyed_event_)));
         impl_destroyed_->RequestCopyOfOutput(std::make_unique<
                                              viz::CopyOutputRequest>(
             viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP,
             base::BindOnce(
                 &LayerTreeHostCopyRequestTestLayerDestroyed::CopyOutputCallback,
-                base::Unretained(this))));
-        // We expect that the RequestCopyOfOutput won't yet return results until
-        // the main is destroyed. So we RunUntilIdle to ensure no PostTask is
-        // currently queued to return the result.
-        CCTestSuite::RunUntilIdle();
-        EXPECT_EQ(0, callback_count_);
+                base::Unretained(this), &impl_destroyed_event_)));
+        EXPECT_FALSE(main_destroyed_event_.IsSignaled());
+        EXPECT_FALSE(impl_destroyed_event_.IsSignaled());
 
         // Destroy the main thread layer right away.
         main_destroyed_->RemoveFromParent();
         main_destroyed_.reset();
 
-        // Should callback with a NULL bitmap, result will be in a PostTask so
-        // RunUntilIdle().
-        CCTestSuite::RunUntilIdle();
-        EXPECT_EQ(1, callback_count_);
-
         // Prevent drawing so we can't make a copy of the impl_destroyed layer.
         layer_tree_host()->SetViewportRectAndScale(
             gfx::Rect(), 1.f, GetCurrentLocalSurfaceIdAllocation());
         break;
       case 2:
-        // Flush the message loops and make sure the callbacks run.
+        // Flush the message loops.
         layer_tree_host()->SetNeedsCommit();
         break;
       case 3:
-        // No drawing means no readback yet.
-        EXPECT_EQ(1, callback_count_);
+        // There is no timing promise of when we'll get the main callback but if
+        // we wait for it, we should receive it before we destroy the impl and
+        // before the impl callback. The resulting bitmap will be empty because
+        // we destroyed it in the first frame before it got a chance to draw.
+        EXPECT_TRUE(
+            main_destroyed_event_.TimedWait(TestTimeouts::action_timeout()));
+        EXPECT_FALSE(impl_destroyed_event_.IsSignaled());
 
         // Destroy the impl thread layer.
         impl_destroyed_->RemoveFromParent();
         impl_destroyed_.reset();
-
-        // No callback yet because it's on the impl side.
-        EXPECT_EQ(1, callback_count_);
         break;
       case 4:
-        // Flush the message loops and make sure the callbacks run.
+        // Flush the message loops.
         layer_tree_host()->SetNeedsCommit();
         break;
       case 5:
-        // We should get another callback with a NULL bitmap.
-        EXPECT_EQ(2, callback_count_);
+        // There is no timing promise of when we'll get the impl callback but if
+        // we wait for it, we should receive it before the end of the test.
+        // The resulting bitmap will be empty because we called
+        // SetViewportRectAndScale() in the first frame before it got a chance
+        // to draw.
+        EXPECT_TRUE(
+            impl_destroyed_event_.TimedWait(TestTimeouts::action_timeout()));
         EndTest();
         break;
     }
   }
 
-  void CopyOutputCallback(std::unique_ptr<viz::CopyOutputResult> result) {
+  void CopyOutputCallback(base::WaitableEvent* event,
+                          std::unique_ptr<viz::CopyOutputResult> result) {
     EXPECT_TRUE(result->IsEmpty());
-    ++callback_count_;
+    event->Signal();
   }
 
-  int callback_count_;
   FakeContentLayerClient client_;
   scoped_refptr<FakePictureLayer> root_;
+  base::WaitableEvent main_destroyed_event_;
   scoped_refptr<FakePictureLayer> main_destroyed_;
+  base::WaitableEvent impl_destroyed_event_;
   scoped_refptr<FakePictureLayer> impl_destroyed_;
 };
 
@@ -379,8 +372,7 @@
     CombineWithCompositorModes({TestRendererType::kGL,
                                 TestRendererType::kSkiaGL}));
 
-// TODO(crbug/1096962): Investigate flakiness and reenable test once fixed.
-TEST_P(LayerTreeHostCopyRequestTestLayerDestroyed, DISABLED_Test) {
+TEST_P(LayerTreeHostCopyRequestTestLayerDestroyed, Test) {
   RunTest(compositor_mode());
 }
 
@@ -1012,9 +1004,7 @@
     LayerTreeHostCopyRequestTest::SetupTree();
   }
 
-  void BeginTest() override {
-    PostSetNeedsCommitToMainThread();
-  }
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
   virtual void RequestCopy(Layer* layer) = 0;
 
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
index bd310eb..2b30e20 100644
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -990,6 +990,7 @@
   "java/res/layout/photo_picker_toolbar.xml",
   "java/res/layout/powered_by_chrome_footer.xml",
   "java/res/layout/preference_text_scale.xml",
+  "java/res/layout/preference_turn_off_sync.xml",
   "java/res/layout/radio_button_group_homepage_preference.xml",
   "java/res/layout/radio_button_group_theme_preference.xml",
   "java/res/layout/recent_tabs_group_item.xml",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index b973434..63248da 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -513,6 +513,7 @@
   "java/src/org/chromium/chrome/browser/directactions/MenuDirectActionHandler.java",
   "java/src/org/chromium/chrome/browser/directactions/SimpleDirectActionHandler.java",
   "java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutController.java",
+  "java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTabHelper.java",
   "java/src/org/chromium/chrome/browser/document/ChromeIntentUtil.java",
   "java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java",
   "java/src/org/chromium/chrome/browser/document/DocumentWebContentsDelegate.java",
@@ -1484,6 +1485,7 @@
   "java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java",
   "java/src/org/chromium/chrome/browser/sync/settings/SignInPreference.java",
   "java/src/org/chromium/chrome/browser/sync/settings/SyncAndServicesSettings.java",
+  "java/src/org/chromium/chrome/browser/sync/settings/SyncOffPreference.java",
   "java/src/org/chromium/chrome/browser/sync/settings/SyncSettingsUtils.java",
   "java/src/org/chromium/chrome/browser/sync/ui/PassphraseActivity.java",
   "java/src/org/chromium/chrome/browser/sync/ui/PassphraseCreationDialogFragment.java",
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni
index 78c6176..34a5395 100644
--- a/chrome/android/chrome_junit_test_java_sources.gni
+++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -195,6 +195,7 @@
   "junit/src/org/chromium/chrome/browser/photo_picker/FileEnumWorkerTaskTest.java",
   "junit/src/org/chromium/chrome/browser/photo_picker/PickerBitmapViewTest.java",
   "junit/src/org/chromium/chrome/browser/policy/EnterpriseInfoTest.java",
+  "junit/src/org/chromium/chrome/browser/preferences/PrefServiceBridgeTest.java",
   "junit/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManagerTest.java",
   "junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceMetricsTest.java",
   "junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java",
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java
index 920c8947..ca92f80 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java
@@ -284,7 +284,9 @@
             return;
         }
 
-        IdentityServicesProvider.get().getIdentityManager().getAccessToken(
+        IdentityManager identityManager = IdentityServicesProvider.get().getIdentityManager(
+                AutofillAssistantUiController.getProfile());
+        identityManager.getAccessToken(
                 mAccount, AUTH_TOKEN_TYPE, new IdentityManager.GetAccessTokenCallback() {
                     @Override
                     public void onGetTokenSuccess(AccessTokenData token) {
@@ -310,7 +312,9 @@
             return;
         }
 
-        IdentityServicesProvider.get().getIdentityManager().invalidateAccessToken(accessToken);
+        IdentityManager identityManager = IdentityServicesProvider.get().getIdentityManager(
+                AutofillAssistantUiController.getProfile());
+        identityManager.invalidateAccessToken(accessToken);
     }
 
     /** Returns the e-mail address that corresponds to the access token or an empty string. */
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderCoordinator.java
index 0eb091c..7653718e 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderCoordinator.java
@@ -11,12 +11,14 @@
 import android.widget.ImageView;
 
 import org.chromium.chrome.autofill_assistant.R;
+import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiController;
 import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderViewBinder.ViewHolder;
 import org.chromium.chrome.browser.signin.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.IdentityServicesProvider;
 import org.chromium.chrome.browser.signin.ProfileDataCache;
 import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.signin.identitymanager.ConsentLevel;
+import org.chromium.components.signin.identitymanager.IdentityManager;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
 import java.util.Collections;
@@ -48,9 +50,10 @@
                 R.dimen.autofill_assistant_profile_size);
         mProfileCache = new ProfileDataCache(context, imageSize);
         mProfileView = mView.findViewById(R.id.profile_image);
+        IdentityManager identityManager = IdentityServicesProvider.get().getIdentityManager(
+                AutofillAssistantUiController.getProfile());
         mSignedInAccountName = CoreAccountInfo.getEmailFrom(
-                IdentityServicesProvider.get().getIdentityManager().getPrimaryAccountInfo(
-                        ConsentLevel.SYNC));
+                identityManager.getPrimaryAccountInfo(ConsentLevel.SYNC));
         setupProfileImage();
 
         // Bind view and mediator through the model.
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayIntegrationTest.java
index eb63c607..40de2ae 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayIntegrationTest.java
@@ -7,6 +7,7 @@
 import static androidx.test.espresso.Espresso.onView;
 import static androidx.test.espresso.action.ViewActions.click;
 import static androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -123,6 +124,74 @@
     }
 
     /**
+     * Showcasts the same element twice in a row, and taps it the second time. Tests that the second
+     * showcast works correctly, even though the showcasted area hasn't changed (see b/161471176).
+     */
+    @Test
+    @MediumTest
+    public void testRepeatedShowCastOnSameElement() throws Exception {
+        SelectorProto element =
+                (SelectorProto) SelectorProto.newBuilder()
+                        .addFilters(
+                                SelectorProto.Filter.newBuilder().setCssSelector("#touch_area_one"))
+                        .build();
+
+        ArrayList<ActionProto> list = new ArrayList<>();
+        list.add(
+                (ActionProto) ActionProto.newBuilder()
+                        .setFocusElement(FocusElementProto.newBuilder()
+                                                 .setElement(element)
+                                                 .setTouchableElementArea(
+                                                         ElementAreaProto.newBuilder().addTouchable(
+                                                                 Rectangle.newBuilder().addElements(
+                                                                         element))))
+                        .build());
+        list.add((ActionProto) ActionProto.newBuilder()
+                         .setPrompt(PromptProto.newBuilder()
+                                            .setMessage("First Prompt")
+                                            .addChoices(PromptProto.Choice.newBuilder().setChip(
+                                                    ChipProto.newBuilder().setText("Continue"))))
+                         .build());
+        list.add(
+                (ActionProto) ActionProto.newBuilder()
+                        .setFocusElement(FocusElementProto.newBuilder()
+                                                 .setElement(element)
+                                                 .setTouchableElementArea(
+                                                         ElementAreaProto.newBuilder().addTouchable(
+                                                                 Rectangle.newBuilder().addElements(
+                                                                         element))))
+                        .build());
+        list.add((ActionProto) ActionProto.newBuilder()
+                         .setPrompt(PromptProto.newBuilder()
+                                            .setMessage("Second Prompt")
+                                            .addChoices(PromptProto.Choice.newBuilder().setChip(
+                                                    ChipProto.newBuilder().setText("Done"))))
+                         .build());
+
+        AutofillAssistantTestScript script = new AutofillAssistantTestScript(
+                (SupportedScriptProto) SupportedScriptProto.newBuilder()
+                        .setPath("autofill_assistant_target_website.html")
+                        .setPresentation(PresentationProto.newBuilder().setAutostart(true).setChip(
+                                ChipProto.newBuilder().setText("Done")))
+                        .build(),
+                list);
+        runScript(script);
+
+        waitUntil(() -> checkElementOnScreen(mTestRule, "touch_area_one"));
+        waitUntilViewMatchesCondition(withText("First Prompt"), isCompletelyDisplayed());
+        onView(withContentDescription("Continue")).perform(click());
+        waitUntilViewMatchesCondition(withText("Second Prompt"), isCompletelyDisplayed());
+
+        // Tapping on the element should remove it from the DOM.
+        assertThat(checkElementExists(mTestRule.getWebContents(), "touch_area_one"), is(true));
+        tapElement(mTestRule, "touch_area_one");
+        waitUntil(() -> !checkElementExists(mTestRule.getWebContents(), "touch_area_one"));
+        // Tapping on the element should be blocked by the overlay.
+        tapElement(mTestRule, "touch_area_four");
+        assertThat(checkElementExists(mTestRule.getWebContents(), "touch_area_four"), is(true));
+    }
+
+    /**
      * Tests that clicking on a document element requiring scrolling works with a showcast.
      */
     @Test
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
index 0175e79..d31be8f 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
@@ -33,10 +33,12 @@
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.lessThan;
 
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.getElementValue;
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.isNextAfterSibling;
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.startAutofillAssistant;
+import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewInRootMatchesCondition;
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition;
 
 import android.support.test.InstrumentationRegistry;
@@ -857,6 +859,20 @@
         onView(withContentDescription("ZIP code*")).perform(scrollTo(), typeText("1234"));
         onView(withContentDescription("Phone*")).perform(scrollTo(), typeText("8008080808"));
         onView(withText("Done")).perform(scrollTo(), click());
+
+        addCreditCardAndSelectAddress();
+        int tryNumber = 0;
+        int maxRetries = 3;
+        while (!hasAddress() && tryNumber++ < maxRetries) {
+            // If the new address is not yet present, we first need to close the popup dialog.
+            Espresso.pressBack();
+            onView(withText("Cancel")).perform(scrollTo(), click());
+            addCreditCardAndSelectAddress();
+        }
+        assertThat(tryNumber, lessThan(maxRetries));
+    }
+
+    private void addCreditCardAndSelectAddress() {
         waitUntilViewMatchesCondition(
                 allOf(withId(R.id.section_title_add_button_label), withText("Add card")),
                 isCompletelyDisplayed());
@@ -867,11 +883,16 @@
         Espresso.closeSoftKeyboard();
         onView(allOf(withId(org.chromium.chrome.R.id.spinner), withChild(withText("Select"))))
                 .perform(scrollTo(), click());
-        onData(anything())
-                .atPosition(1 /* address of John, 0 is SELECT (empty) */)
-                .inRoot(withDecorView(withClassName(containsString("Popup"))))
-                .perform(click());
-        waitUntilViewMatchesCondition(withText(containsString("John Doe")), isDisplayed());
+    }
+
+    private boolean hasAddress() {
+        try {
+            waitUntilViewInRootMatchesCondition(withText(containsString("John Doe")),
+                    withDecorView(withClassName(containsString("Popup"))), isDisplayed());
+            return true;
+        } catch (AssertionError e) {
+            return false;
+        }
     }
 
     private void runScript(AutofillAssistantTestScript script) {
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java
index 2320dbcd..17d46367 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java
@@ -31,6 +31,7 @@
 import androidx.annotation.Nullable;
 import androidx.coordinatorlayout.widget.CoordinatorLayout;
 import androidx.test.espresso.NoMatchingViewException;
+import androidx.test.espresso.Root;
 import androidx.test.espresso.UiController;
 import androidx.test.espresso.ViewAction;
 import androidx.test.espresso.ViewAssertion;
@@ -397,6 +398,24 @@
         waitUntilViewMatchesCondition(matcher, condition, DEFAULT_MAX_TIME_TO_POLL);
     }
 
+    /**
+     * Same as {@link #waitUntilViewMatchesCondition(Matcher, Matcher)} but also uses {@code
+     * rootMatcher} to select the correct window.
+     */
+    public static void waitUntilViewInRootMatchesCondition(
+            Matcher<View> matcher, Matcher<Root> rootMatcher, Matcher<View> condition) {
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            try {
+                onView(matcher).inRoot(rootMatcher).check(matches(condition));
+            } catch (NoMatchingViewException | AssertionError e) {
+                // Note: all other exceptions are let through, in particular
+                // AmbiguousViewMatcherException.
+                throw new CriteriaNotSatisfiedException(
+                        "Timeout while waiting for " + matcher + " to satisfy " + condition);
+            }
+        }, DEFAULT_MAX_TIME_TO_POLL, DEFAULT_POLLING_INTERVAL);
+    }
+
     /** @see {@link #waitUntilViewMatchesCondition(Matcher, Matcher)} */
     public static void waitUntilViewMatchesCondition(
             Matcher<View> matcher, Matcher<View> condition, long maxTimeoutMs) {
diff --git a/chrome/android/java/res/layout/preference_turn_off_sync.xml b/chrome/android/java/res/layout/preference_turn_off_sync.xml
new file mode 100644
index 0000000..6a82ab9
--- /dev/null
+++ b/chrome/android/java/res/layout/preference_turn_off_sync.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/PreferenceLayout"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center">
+
+    <TextView
+        android:id="@+id/turn_off_sync"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/turn_off_sync"
+        android:textAppearance="@style/TextAppearance.TextMediumThick.Blue"
+        android:gravity="center"/>
+
+</LinearLayout>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutController.java b/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutController.java
index fe0f63c..6334e63 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutController.java
@@ -14,29 +14,21 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.UserData;
-import org.chromium.base.UserDataHost;
 import org.chromium.blink.mojom.ViewportFit;
-import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.tab.EmptyTabObserver;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabObserver;
-import org.chromium.chrome.browser.tab.TabSelectionType;
 import org.chromium.components.browser_ui.widget.InsetObserverView;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsObserver;
 import org.chromium.ui.base.WindowAndroid;
 
 /**
- * Controls the display cutout state for the tab.
+ * Controls the display safe area for a {@link WebContents} and the cutout mode for an {@link
+ * Activity} window.
+ *
+ * The WebContents is updated with the safe area continuously, as long as {@link
+ * Delegate#getAttachedActivity()} returns a non-null value. The cutout mode is set on the
+ * Activity's window only in P+, and only when the associated WebContents is fullscreen.
  */
-public class DisplayCutoutController implements InsetObserverView.WindowInsetObserver, UserData {
-    private static final Class<DisplayCutoutController> USER_DATA_KEY =
-            DisplayCutoutController.class;
-
-    /** The tab that this controller belongs to. */
-    private Tab mTab;
-
+public class DisplayCutoutController implements InsetObserverView.WindowInsetObserver {
     /** {@link Window} of the current {@link Activity}. */
     private Window mWindow;
 
@@ -49,73 +41,47 @@
      */
     private @Nullable InsetObserverView mInsetObserverView;
 
-    /** Listens to various Tab events. */
-    private final TabObserver mTabObserver = new EmptyTabObserver() {
-        @Override
-        public void onShown(Tab tab, @TabSelectionType int type) {
-            assert tab == mTab;
+    /** An interface for providing embedder-specific behavior to the controller. */
+    interface Delegate {
+        /** Returns the activity this controller is associated with, if there is one. */
+        @Nullable
+        Activity getAttachedActivity();
 
-            // Force a layout update if we are now being shown.
-            maybeUpdateLayout();
-        }
+        /**
+         * Returns the {@link WebContents} this controller should update the safe area for, if
+         * there is one.
+         */
+        @Nullable
+        WebContents getWebContents();
 
-        @Override
-        public void onInteractabilityChanged(Tab tab, boolean interactable) {
-            // Force a layout update if the tab is now in the foreground.
-            maybeUpdateLayout();
-        }
+        /** Returns the view this controller uses for safe area updates, if there is one. */
+        @Nullable
+        InsetObserverView getInsetObserverView();
 
-        @Override
-        public void onActivityAttachmentChanged(Tab tab, @Nullable WindowAndroid window) {
-            assert tab == mTab;
+        /** Returns whether the user can interact with the associated WebContents/UI element. */
+        boolean isInteractable();
+    }
+    private final Delegate mDelegate;
 
-            if (window != null) {
-                maybeAddInsetObserver(tab.getWindowAndroid().getActivity().get());
-            } else {
-                maybeRemoveInsetObserver();
-            }
-        }
-    };
-
-    public static DisplayCutoutController from(Tab tab) {
-        UserDataHost host = tab.getUserDataHost();
-        DisplayCutoutController controller = host.getUserData(USER_DATA_KEY);
-        return controller == null
-                ? host.setUserData(USER_DATA_KEY, new DisplayCutoutController(tab))
-                : controller;
+    public DisplayCutoutController(Delegate delegate) {
+        mDelegate = delegate;
+        maybeAddInsetObserver();
     }
 
-    /**
-     * Constructs a new DisplayCutoutController for a specific tab.
-     * @param tab The tab that this controller belongs to.
-     */
-    @VisibleForTesting
-    DisplayCutoutController(Tab tab) {
-        mTab = tab;
-
-        tab.addObserver(mTabObserver);
-        maybeAddInsetObserver(tab.getWindowAndroid().getActivity().get());
-    }
-
-    /**
-     * Add an observer to {@link InsetObserverView} if we have not already added
-     * one.
-     */
-    private void maybeAddInsetObserver(Activity activity) {
+    /** Add an observer to {@link InsetObserverView} if we have not already added one. */
+    void maybeAddInsetObserver() {
+        Activity activity = mDelegate.getAttachedActivity();
         if (mInsetObserverView != null || activity == null) return;
 
-        mInsetObserverView = ((ChromeActivity) activity).getInsetObserverView();
+        mInsetObserverView = mDelegate.getInsetObserverView();
 
         if (mInsetObserverView == null) return;
         mInsetObserverView.addObserver(this);
         mWindow = activity.getWindow();
     }
 
-    /**
-     * Remove the observer added to {@link InsetObserverView} if we have added
-     * one.
-     */
-    private void maybeRemoveInsetObserver() {
+    /** Remove the observer added to {@link InsetObserverView} if we have added one. */
+    void maybeRemoveInsetObserver() {
         if (mInsetObserverView == null) return;
 
         mInsetObserverView.removeObserver(this);
@@ -123,9 +89,7 @@
         mWindow = null;
     }
 
-    @Override
     public void destroy() {
-        mTab.removeObserver(mTabObserver);
         maybeRemoveInsetObserver();
     }
 
@@ -134,6 +98,10 @@
      * @param value The new viewport fit value.
      */
     public void setViewportFit(@WebContentsObserver.ViewportFitType int value) {
+        if (value != ViewportFit.AUTO) {
+            assert mDelegate.getWebContents().isFullscreenForCurrentTab();
+        }
+
         if (value == mViewportFit) return;
 
         mViewportFit = value;
@@ -143,7 +111,7 @@
     /** Implements {@link WindowInsetsObserver}. */
     @Override
     public void onSafeAreaChanged(Rect area) {
-        WebContents webContents = mTab.getWebContents();
+        WebContents webContents = mDelegate.getWebContents();
         if (webContents == null) return;
 
         float dipScale = getDipScale();
@@ -163,18 +131,13 @@
      * @param dipScale The devices dip scale as an integer.
      * @return The CSS pixel value adjusted for scale.
      */
-    private int adjustInsetForScale(int inset, float dipScale) {
+    private static int adjustInsetForScale(int inset, float dipScale) {
         return (int) Math.ceil(inset / dipScale);
     }
 
     @VisibleForTesting
-    static void initForTesting(UserDataHost host, DisplayCutoutController controller) {
-        host.setUserData(USER_DATA_KEY, controller);
-    }
-
-    @VisibleForTesting
     protected float getDipScale() {
-        return mTab.getWindowAndroid().getDisplay().getDipScale();
+        return mDelegate.getWebContents().getTopLevelNativeWindow().getDisplay().getDipScale();
     }
 
     /**
@@ -186,7 +149,7 @@
     @TargetApi(Build.VERSION_CODES.P)
     protected int getDisplayCutoutMode() {
         // If we are not interactable then force the default mode.
-        if (!mTab.isUserInteractable()) {
+        if (!mDelegate.isInteractable()) {
             return LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
         }
 
@@ -223,4 +186,12 @@
         attributes.layoutInDisplayCutoutMode = getDisplayCutoutMode();
         setWindowAttributes(attributes);
     }
+
+    void onActivityAttachmentChanged(@Nullable WindowAndroid window) {
+        if (window == null) {
+            maybeRemoveInsetObserver();
+        } else {
+            maybeAddInsetObserver();
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTabHelper.java
new file mode 100644
index 0000000..ca3eb370
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTabHelper.java
@@ -0,0 +1,127 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.display_cutout;
+
+import android.app.Activity;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import org.chromium.base.UserData;
+import org.chromium.base.UserDataHost;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabObserver;
+import org.chromium.chrome.browser.tab.TabSelectionType;
+import org.chromium.components.browser_ui.widget.InsetObserverView;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContentsObserver;
+import org.chromium.ui.base.WindowAndroid;
+
+/**
+ * Wraps a {@link DisplayCutoutController} for a Chrome {@link Tab}.
+ *
+ * This will only be created once the tab sets a non-default viewport fit.
+ */
+public class DisplayCutoutTabHelper implements UserData {
+    private static final Class<DisplayCutoutTabHelper> USER_DATA_KEY = DisplayCutoutTabHelper.class;
+
+    /** The tab that this object belongs to. */
+    private Tab mTab;
+
+    @VisibleForTesting
+    DisplayCutoutController mCutoutController;
+
+    /** Listens to various Tab events. */
+    private final TabObserver mTabObserver = new EmptyTabObserver() {
+        @Override
+        public void onShown(Tab tab, @TabSelectionType int type) {
+            assert tab == mTab;
+
+            // Force a layout update if we are now being shown.
+            mCutoutController.maybeUpdateLayout();
+        }
+
+        @Override
+        public void onInteractabilityChanged(Tab tab, boolean interactable) {
+            // Force a layout update if the tab is now in the foreground.
+            mCutoutController.maybeUpdateLayout();
+        }
+
+        @Override
+        public void onActivityAttachmentChanged(Tab tab, @Nullable WindowAndroid window) {
+            assert tab == mTab;
+
+            mCutoutController.onActivityAttachmentChanged(window);
+        }
+    };
+
+    public static DisplayCutoutTabHelper from(Tab tab) {
+        UserDataHost host = tab.getUserDataHost();
+        DisplayCutoutTabHelper tabHelper = host.getUserData(USER_DATA_KEY);
+        return tabHelper == null ? host.setUserData(USER_DATA_KEY, new DisplayCutoutTabHelper(tab))
+                                 : tabHelper;
+    }
+
+    @VisibleForTesting
+    static class ChromeDisplayCutoutDelegate implements DisplayCutoutController.Delegate {
+        private Tab mTab;
+
+        ChromeDisplayCutoutDelegate(Tab tab) {
+            mTab = tab;
+        }
+
+        @Override
+        public Activity getAttachedActivity() {
+            return mTab.getWindowAndroid().getActivity().get();
+        }
+        @Override
+        public WebContents getWebContents() {
+            return mTab.getWebContents();
+        }
+        @Override
+        public InsetObserverView getInsetObserverView() {
+            Activity activity = getAttachedActivity();
+            return activity == null ? null : ((ChromeActivity) activity).getInsetObserverView();
+        }
+        @Override
+        public boolean isInteractable() {
+            return mTab.isUserInteractable();
+        }
+    }
+
+    /**
+     * Constructs a new DisplayCutoutTabHelper for a specific tab.
+     * @param tab The tab that this object belongs to.
+     */
+    @VisibleForTesting
+    DisplayCutoutTabHelper(Tab tab) {
+        mTab = tab;
+        tab.addObserver(mTabObserver);
+        mCutoutController = new DisplayCutoutController(new ChromeDisplayCutoutDelegate(mTab));
+    }
+
+    /**
+     * Set the viewport fit value for the tab.
+     * @param value The new viewport fit value.
+     */
+    public void setViewportFit(@WebContentsObserver.ViewportFitType int value) {
+        mCutoutController.setViewportFit(value);
+    }
+
+    @Override
+    public void destroy() {
+        mTab.removeObserver(mTabObserver);
+        mCutoutController.destroy();
+    }
+
+    @VisibleForTesting
+    static void initForTesting(Tab tab, DisplayCutoutController controller) {
+        DisplayCutoutTabHelper tabHelper = new DisplayCutoutTabHelper(tab);
+        tabHelper.mCutoutController = controller;
+        tab.getUserDataHost().setUserData(USER_DATA_KEY, tabHelper);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncOffPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncOffPreference.java
new file mode 100644
index 0000000..6084f9ec
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncOffPreference.java
@@ -0,0 +1,23 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.sync.settings;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import androidx.preference.DialogPreference;
+
+import org.chromium.chrome.R;
+
+/**
+ * A preference that displays "Sign out and turn off sync" button in {@link ManageSyncSettings}.
+ */
+public class SyncOffPreference extends DialogPreference {
+    public SyncOffPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        setLayoutResource(R.layout.preference_turn_off_sync);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
index 6720286d..766b6a96 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
@@ -76,5 +76,8 @@
   ],
   'TabViewManagerImpl\.java': [
     "+chrome/browser/browser_controls/android/java/src/org/chromium/chrome/browser/browser_controls/BrowserControlsMarginSupplier.java",
+  ],
+  'TabWebContentsObserver\.java': [
+    "+chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTabHelper.java",
   ]
 }
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 b319303f..8ba6590 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
@@ -20,7 +20,7 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.SwipeRefreshHandler;
-import org.chromium.chrome.browser.display_cutout.DisplayCutoutController;
+import org.chromium.chrome.browser.display_cutout.DisplayCutoutTabHelper;
 import org.chromium.chrome.browser.media.MediaCaptureNotificationService;
 import org.chromium.chrome.browser.policy.PolicyAuditor;
 import org.chromium.chrome.browser.policy.PolicyAuditor.AuditEvent;
@@ -347,7 +347,7 @@
 
         @Override
         public void viewportFitChanged(@WebContentsObserver.ViewportFitType int value) {
-            DisplayCutoutController.from(mTab).setViewportFit(value);
+            DisplayCutoutTabHelper.from(mTab).setViewportFit(value);
         }
 
         @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTestRule.java
index 96369ce9..8b1b782 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTestRule.java
@@ -59,8 +59,8 @@
         private boolean mDeviceHasCutout = true;
         private float mDipScale = 1;
 
-        TestDisplayCutoutController(Tab tab) {
-            super(tab);
+        TestDisplayCutoutController(DisplayCutoutController.Delegate delegate) {
+            super(delegate);
         }
 
         @Override
@@ -159,10 +159,11 @@
 
     protected void setUp() {
         mTab = getActivity().getActivityTab();
-        mTestController = new TestDisplayCutoutController(mTab);
+        mTestController = new TestDisplayCutoutController(
+                new DisplayCutoutTabHelper.ChromeDisplayCutoutDelegate(mTab));
+
         TestThreadUtils.runOnUiThreadBlocking(
-                () -> DisplayCutoutController.initForTesting(
-                                mTab.getUserDataHost(), mTestController));
+                () -> DisplayCutoutTabHelper.initForTesting(mTab, mTestController));
 
         mListener = new FullscreenToggleObserver();
         getActivity().getFullscreenManager().addObserver(mListener);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AndroidSyncSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AndroidSyncSettingsTest.java
index 353a873..db74470 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AndroidSyncSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AndroidSyncSettingsTest.java
@@ -19,15 +19,15 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.Callback;
+import org.chromium.base.FeatureList;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.sync.AndroidSyncSettings.AndroidSyncSettingsObserver;
-import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
-import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
-import org.chromium.chrome.test.util.browser.Features.JUnitProcessor;
+import org.chromium.chrome.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.signin.AccountUtils;
 import org.chromium.components.signin.test.util.FakeAccountManagerFacade;
@@ -41,7 +41,6 @@
  * Tests for AndroidSyncSettings.
  */
 @RunWith(BaseJUnit4ClassRunner.class)
-@DisableFeatures(ChromeFeatureList.DECOUPLE_SYNC_FROM_ANDROID_MASTER_SYNC)
 public class AndroidSyncSettingsTest {
     private static class CountingMockSyncContentResolverDelegate
             extends MockSyncContentResolverDelegate {
@@ -106,8 +105,11 @@
         }
     }
 
+    // |mChromeBrowserRule| is used to wait for the native feature list to initialize.
     @Rule
-    public TestRule mProcessorRule = new JUnitProcessor();
+    public TestRule mChromeBrowserRule = new ChromeBrowserTestRule();
+    @Rule
+    public TestRule mProcessorRule = new Features.JUnitProcessor();
 
     private AndroidSyncSettings mAndroidSyncSettings;
     private CountingMockSyncContentResolverDelegate mSyncContentResolverDelegate;
@@ -120,6 +122,8 @@
 
     @Before
     public void setUp() throws Exception {
+        FeatureList.setTestCanUseDefaultsForTesting();
+
         mNumberOfCallsToWait = 0;
         mCallbackHelper = new CallbackHelper();
         setupTestAccounts();
@@ -148,6 +152,16 @@
         fakeAccountManagerFacade.addAccount(mAlternateAccount);
     }
 
+    private void setMasterSyncAllowsChromeSync() throws InterruptedException {
+        if (!ChromeFeatureList.isEnabled(
+                    ChromeFeatureList.DECOUPLE_SYNC_FROM_ANDROID_MASTER_SYNC)) {
+            mSyncContentResolverDelegate.setMasterSyncAutomatically(true);
+            mSyncContentResolverDelegate.waitForLastNotificationCompleted();
+        }
+        // If DecoupleSyncFromAndroidMasterSync is enabled, no need for any
+        // setup since master sync doesn't influence sync.
+    }
+
     @After
     public void tearDown() throws Exception {
         if (mNumberOfCallsToWait > 0) mCallbackHelper.waitForCallback(0, mNumberOfCallsToWait);
@@ -213,22 +227,28 @@
     public void testToggleMasterSyncFromSettings() throws InterruptedException {
         mSyncContentResolverDelegate.setMasterSyncAutomatically(true);
         mSyncContentResolverDelegate.waitForLastNotificationCompleted();
-        Assert.assertTrue("master sync should be set",
-                mAndroidSyncSettings.doesMasterSyncSettingAllowChromeSync());
+        Assert.assertTrue(mAndroidSyncSettings.doesMasterSyncSettingAllowChromeSync());
 
         mSyncContentResolverDelegate.setMasterSyncAutomatically(false);
         mSyncContentResolverDelegate.waitForLastNotificationCompleted();
-        Assert.assertFalse("master sync should be unset",
-                mAndroidSyncSettings.doesMasterSyncSettingAllowChromeSync());
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.DECOUPLE_SYNC_FROM_ANDROID_MASTER_SYNC)) {
+            Assert.assertTrue(
+                    "when DecoupleSyncFromAndroidMasterSync is enabled, sync should be allowed "
+                            + "even though master sync is disabled",
+                    mAndroidSyncSettings.doesMasterSyncSettingAllowChromeSync());
+        } else {
+            Assert.assertFalse(
+                    "when DecoupleSyncFromAndroidMasterSync is disabled, sync shouldn't be allowed "
+                            + "if master sync is disabled",
+                    mAndroidSyncSettings.doesMasterSyncSettingAllowChromeSync());
+        }
     }
 
     @Test
     @SmallTest
     @Feature({"Sync"})
     public void testToggleChromeSyncFromSettings() throws InterruptedException {
-        // Turn on syncability.
-        mSyncContentResolverDelegate.setMasterSyncAutomatically(true);
-        mSyncContentResolverDelegate.waitForLastNotificationCompleted();
+        setMasterSyncAllowsChromeSync();
 
         // First sync
         mSyncContentResolverDelegate.setIsSyncable(mAccount, mAuthority, 1);
@@ -253,24 +273,29 @@
         Assert.assertTrue(
                 "sync should be set for chrome app", mAndroidSyncSettings.isChromeSyncEnabled());
 
-        // Disabled from master sync
+        // Disable master sync
         mSyncContentResolverDelegate.setMasterSyncAutomatically(false);
         mSyncContentResolverDelegate.waitForLastNotificationCompleted();
-        Assert.assertFalse(
-                "sync should be disabled due to master sync", mAndroidSyncSettings.isSyncEnabled());
-        Assert.assertFalse("master sync should be disabled",
-                mAndroidSyncSettings.doesMasterSyncSettingAllowChromeSync());
         Assert.assertTrue(
                 "sync should be set for chrome app", mAndroidSyncSettings.isChromeSyncEnabled());
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.DECOUPLE_SYNC_FROM_ANDROID_MASTER_SYNC)) {
+            Assert.assertTrue("sync should be enabled despite master sync being disabled",
+                    mAndroidSyncSettings.isSyncEnabled());
+            Assert.assertTrue("master sync should allow sync",
+                    mAndroidSyncSettings.doesMasterSyncSettingAllowChromeSync());
+        } else {
+            Assert.assertFalse("sync should be disabled due to master sync disabled",
+                    mAndroidSyncSettings.isSyncEnabled());
+            Assert.assertFalse("master sync should not allow sync",
+                    mAndroidSyncSettings.doesMasterSyncSettingAllowChromeSync());
+        }
     }
 
     @Test
     @SmallTest
     @Feature({"Sync"})
     public void testToggleAccountSyncFromApplication() throws InterruptedException {
-        // Turn on syncability.
-        mSyncContentResolverDelegate.setMasterSyncAutomatically(true);
-        mSyncContentResolverDelegate.waitForLastNotificationCompleted();
+        setMasterSyncAllowsChromeSync();
 
         enableChromeSyncOnUiThread();
         mSyncContentResolverDelegate.waitForLastNotificationCompleted();
@@ -285,9 +310,7 @@
     @SmallTest
     @Feature({"Sync"})
     public void testToggleSyncabilityForMultipleAccounts() throws InterruptedException {
-        // Turn on syncability.
-        mSyncContentResolverDelegate.setMasterSyncAutomatically(true);
-        mSyncContentResolverDelegate.waitForLastNotificationCompleted();
+        setMasterSyncAllowsChromeSync();
 
         enableChromeSyncOnUiThread();
         mSyncContentResolverDelegate.waitForLastNotificationCompleted();
@@ -316,9 +339,7 @@
     @SmallTest
     @Feature({"Sync"})
     public void testSyncSettingsCaching() throws InterruptedException {
-        // Turn on syncability.
-        mSyncContentResolverDelegate.setMasterSyncAutomatically(true);
-        mSyncContentResolverDelegate.waitForLastNotificationCompleted();
+        setMasterSyncAllowsChromeSync();
 
         enableChromeSyncOnUiThread();
         mSyncContentResolverDelegate.waitForLastNotificationCompleted();
@@ -371,9 +392,7 @@
     @SmallTest
     @Feature({"Sync"})
     public void testAndroidSyncSettingsPostsNotifications() throws InterruptedException {
-        // Turn on syncability.
-        mSyncContentResolverDelegate.setMasterSyncAutomatically(true);
-        mSyncContentResolverDelegate.waitForLastNotificationCompleted();
+        setMasterSyncAllowsChromeSync();
 
         mSyncSettingsObserver.clearNotification();
         mAndroidSyncSettings.enableChromeSync();
@@ -452,7 +471,9 @@
     @Test
     @SmallTest
     @Feature({"Sync"})
-    @EnableFeatures(ChromeFeatureList.DECOUPLE_SYNC_FROM_ANDROID_MASTER_SYNC)
+    @Features.EnableFeatures(ChromeFeatureList.DECOUPLE_SYNC_FROM_ANDROID_MASTER_SYNC)
+    // TODO(crbug.com/1105795): Remove this test after DecoupleSyncFromAndroidMasterSync has
+    // launched, since testToggleChromeSyncFromSettings() covers the same functionality.
     public void testSyncStateDoesNotDependOnMasterSync() throws InterruptedException {
         mSyncContentResolverDelegate.setSyncAutomatically(mAccount, mAuthority, true);
         mSyncContentResolverDelegate.setMasterSyncAutomatically(false);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
index 7ad70be..4fd6dcfb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
@@ -12,16 +12,19 @@
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.IdentityServicesProvider;
 import org.chromium.chrome.browser.signin.SigninHelper;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.signin.MockChangeEventChecker;
 import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
 import org.chromium.content_public.browser.test.util.Criteria;
@@ -36,6 +39,8 @@
 public class SyncTest {
     @Rule
     public SyncTestRule mSyncTestRule = new SyncTestRule();
+    @Rule
+    public TestRule mProcessorRule = new Features.JUnitProcessor();
 
     private static final String TAG = "SyncTest";
 
@@ -152,6 +157,7 @@
 
     @Test
     @LargeTest
+    @Features.DisableFeatures(ChromeFeatureList.DECOUPLE_SYNC_FROM_ANDROID_MASTER_SYNC)
     @Feature({"Sync"})
     public void testStopAndStartSyncThroughAndroidMasterSync() {
         mSyncTestRule.setUpAccountAndSignInForTesting();
@@ -171,6 +177,7 @@
     @Test
     @LargeTest
     @Feature({"Sync"})
+    @Features.DisableFeatures(ChromeFeatureList.DECOUPLE_SYNC_FROM_ANDROID_MASTER_SYNC)
     @DisabledTest(message = "Test is flaky crbug.com/1100890")
     public void testReenableMasterSyncFirst() {
         Account account = mSyncTestRule.setUpAccountAndSignInForTesting();
@@ -203,6 +210,7 @@
 
     @Test
     @LargeTest
+    @Features.DisableFeatures(ChromeFeatureList.DECOUPLE_SYNC_FROM_ANDROID_MASTER_SYNC)
     @Feature({"Sync"})
     public void testReenableChromeSyncFirst() {
         Account account = mSyncTestRule.setUpAccountAndSignInForTesting();
@@ -240,6 +248,7 @@
 
     @Test
     @LargeTest
+    @Features.DisableFeatures(ChromeFeatureList.DECOUPLE_SYNC_FROM_ANDROID_MASTER_SYNC)
     @Feature({"Sync"})
     public void testMasterSyncBlocksSyncStart() {
         mSyncTestRule.setUpAccountAndSignInForTesting();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutControllerTest.java
index d12451b7..6accbf56 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutControllerTest.java
@@ -31,6 +31,7 @@
 import org.chromium.chrome.browser.tab.TabObserver;
 import org.chromium.chrome.browser.tab.TabSelectionType;
 import org.chromium.components.browser_ui.widget.InsetObserverView;
+import org.chromium.content_public.browser.WebContents;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 import org.chromium.ui.base.WindowAndroid;
 
@@ -46,6 +47,9 @@
     private TabImpl mTab;
 
     @Mock
+    private WebContents mWebContents;
+
+    @Mock
     private WindowAndroid mWindowAndroid;
 
     @Mock
@@ -60,7 +64,8 @@
     @Mock
     private InsetObserverView mInsetObserver;
 
-    private DisplayCutoutController mDisplayCutoutController;
+    private DisplayCutoutTabHelper mDisplayCutoutTabHelper;
+    private DisplayCutoutController mController;
 
     private WeakReference<Activity> mActivityRef;
 
@@ -75,28 +80,32 @@
         when(mChromeActivity.getWindow()).thenReturn(mWindow);
         when(mWindow.getAttributes()).thenReturn(new LayoutParams());
         when(mTab.getWindowAndroid()).thenReturn(mWindowAndroid);
+        when(mTab.getWebContents()).thenReturn(mWebContents);
+        when(mWebContents.isFullscreenForCurrentTab()).thenReturn(true);
         when(mWindowAndroid.getActivity()).thenReturn(mActivityRef);
         when(mChromeActivity.getInsetObserverView()).thenReturn(mInsetObserver);
 
-        mDisplayCutoutController = spy(new DisplayCutoutController(mTab));
+        mDisplayCutoutTabHelper = spy(new DisplayCutoutTabHelper(mTab));
+        mController = spy(mDisplayCutoutTabHelper.mCutoutController);
+        mDisplayCutoutTabHelper.mCutoutController = mController;
     }
 
     @Test
     @SmallTest
     public void testViewportFitUpdate() {
-        verify(mDisplayCutoutController, never()).maybeUpdateLayout();
+        verify(mController, never()).maybeUpdateLayout();
 
-        mDisplayCutoutController.setViewportFit(ViewportFit.COVER);
-        verify(mDisplayCutoutController).maybeUpdateLayout();
+        mDisplayCutoutTabHelper.setViewportFit(ViewportFit.COVER);
+        verify(mController).maybeUpdateLayout();
     }
 
     @Test
     @SmallTest
     public void testViewportFitUpdateNotChanged() {
-        verify(mDisplayCutoutController, never()).maybeUpdateLayout();
+        verify(mController, never()).maybeUpdateLayout();
 
-        mDisplayCutoutController.setViewportFit(ViewportFit.AUTO);
-        verify(mDisplayCutoutController, never()).maybeUpdateLayout();
+        mDisplayCutoutTabHelper.setViewportFit(ViewportFit.AUTO);
+        verify(mController, never()).maybeUpdateLayout();
     }
 
     @Test
@@ -104,9 +113,9 @@
     public void testCutoutModeWhenAutoAndInteractable() {
         when(mTab.isUserInteractable()).thenReturn(true);
 
-        mDisplayCutoutController.setViewportFit(ViewportFit.AUTO);
+        mDisplayCutoutTabHelper.setViewportFit(ViewportFit.AUTO);
         Assert.assertEquals(LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT,
-                mDisplayCutoutController.getDisplayCutoutMode());
+                mController.getDisplayCutoutMode());
     }
 
     @Test
@@ -114,9 +123,9 @@
     public void testCutoutModeWhenCoverAndInteractable() {
         when(mTab.isUserInteractable()).thenReturn(true);
 
-        mDisplayCutoutController.setViewportFit(ViewportFit.COVER);
+        mDisplayCutoutTabHelper.setViewportFit(ViewportFit.COVER);
         Assert.assertEquals(LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES,
-                mDisplayCutoutController.getDisplayCutoutMode());
+                mController.getDisplayCutoutMode());
     }
 
     @Test
@@ -124,9 +133,9 @@
     public void testCutoutModeWhenCoverForcedAndInteractable() {
         when(mTab.isUserInteractable()).thenReturn(true);
 
-        mDisplayCutoutController.setViewportFit(ViewportFit.COVER_FORCED_BY_USER_AGENT);
+        mDisplayCutoutTabHelper.setViewportFit(ViewportFit.COVER_FORCED_BY_USER_AGENT);
         Assert.assertEquals(LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES,
-                mDisplayCutoutController.getDisplayCutoutMode());
+                mController.getDisplayCutoutMode());
     }
 
     @Test
@@ -134,41 +143,41 @@
     public void testCutoutModeWhenContainAndInteractable() {
         when(mTab.isUserInteractable()).thenReturn(true);
 
-        mDisplayCutoutController.setViewportFit(ViewportFit.CONTAIN);
+        mDisplayCutoutTabHelper.setViewportFit(ViewportFit.CONTAIN);
         Assert.assertEquals(LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER,
-                mDisplayCutoutController.getDisplayCutoutMode());
+                mController.getDisplayCutoutMode());
     }
 
     @Test
     @SmallTest
     public void testCutoutModeWhenAutoAndNotInteractable() {
-        mDisplayCutoutController.setViewportFit(ViewportFit.AUTO);
+        mDisplayCutoutTabHelper.setViewportFit(ViewportFit.AUTO);
         Assert.assertEquals(LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT,
-                mDisplayCutoutController.getDisplayCutoutMode());
+                mController.getDisplayCutoutMode());
     }
 
     @Test
     @SmallTest
     public void testCutoutModeWhenCoverAndNotInteractable() {
-        mDisplayCutoutController.setViewportFit(ViewportFit.COVER);
+        mDisplayCutoutTabHelper.setViewportFit(ViewportFit.COVER);
         Assert.assertEquals(LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT,
-                mDisplayCutoutController.getDisplayCutoutMode());
+                mController.getDisplayCutoutMode());
     }
 
     @Test
     @SmallTest
     public void testCutoutModeWhenCoverForcedAndNotInteractable() {
-        mDisplayCutoutController.setViewportFit(ViewportFit.COVER_FORCED_BY_USER_AGENT);
+        mDisplayCutoutTabHelper.setViewportFit(ViewportFit.COVER_FORCED_BY_USER_AGENT);
         Assert.assertEquals(LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT,
-                mDisplayCutoutController.getDisplayCutoutMode());
+                mController.getDisplayCutoutMode());
     }
 
     @Test
     @SmallTest
     public void testCutoutModeWhenContainAndNotInteractable() {
-        mDisplayCutoutController.setViewportFit(ViewportFit.CONTAIN);
+        mDisplayCutoutTabHelper.setViewportFit(ViewportFit.CONTAIN);
         Assert.assertEquals(LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT,
-                mDisplayCutoutController.getDisplayCutoutMode());
+                mController.getDisplayCutoutMode());
     }
 
     @Test
@@ -176,7 +185,7 @@
     public void testLayoutOnInteractability_True() {
         // In this test we are checking for a side effect of maybeUpdateLayout.
         // This is because the tab observer holds a reference to the original
-        // mDisplayCutoutController and not the spied one.
+        // mDisplayCutoutTabHelper and not the spied one.
         verify(mTab).addObserver(mTabObserverCaptor.capture());
         reset(mTab);
 
@@ -189,7 +198,7 @@
     public void testLayoutOnInteractability_False() {
         // In this test we are checking for a side effect of maybeUpdateLayout.
         // This is because the tab observer holds a reference to the original
-        // mDisplayCutoutController and not the spied one.
+        // mDisplayCutoutTabHelper and not the spied one.
         verify(mTab).addObserver(mTabObserverCaptor.capture());
         reset(mTab);
 
@@ -214,7 +223,7 @@
     public void testLayoutOnShown() {
         // In this test we are checking for a side effect of maybeUpdateLayout.
         // This is because the tab observer holds a reference to the original
-        // mDisplayCutoutController and not the spied one.
+        // mDisplayCutoutTabHelper and not the spied one.
         verify(mTab).addObserver(mTabObserverCaptor.capture());
         reset(mTab);
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/preferences/PrefServiceBridgeTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/preferences/PrefServiceBridgeTest.java
new file mode 100644
index 0000000..706b1cb
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/preferences/PrefServiceBridgeTest.java
@@ -0,0 +1,111 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// generate_java_test.py
+
+package org.chromium.chrome.browser.preferences;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.JniMocker;
+
+/** Unit tests for {@link PrefServiceBridge}. */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class PrefServiceBridgeTest {
+    private static final String PREF = "42";
+
+    @Rule
+    public JniMocker mocker = new JniMocker();
+    @Mock
+    private PrefServiceBridge.Natives mNativeMock;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mocker.mock(PrefServiceBridgeJni.TEST_HOOKS, mNativeMock);
+    }
+
+    @Test
+    public void testGetBoolean() {
+        boolean expected = false;
+
+        PrefServiceBridge prefServiceBridge = new PrefServiceBridge();
+        doReturn(expected).when(mNativeMock).getBoolean(PREF);
+
+        assertEquals(expected, prefServiceBridge.getBoolean(PREF));
+    }
+
+    @Test
+    public void testSetBoolean() {
+        boolean value = true;
+
+        PrefServiceBridge prefServiceBridge = new PrefServiceBridge();
+        prefServiceBridge.setBoolean(PREF, value);
+
+        verify(mNativeMock).setBoolean(eq(PREF), eq(value));
+    }
+
+    @Test
+    public void testGetInteger() {
+        int expected = 26;
+
+        PrefServiceBridge prefServiceBridge = new PrefServiceBridge();
+        doReturn(expected).when(mNativeMock).getInteger(PREF);
+
+        assertEquals(expected, prefServiceBridge.getInteger(PREF));
+    }
+
+    @Test
+    public void testSetInteger() {
+        int value = 62;
+
+        PrefServiceBridge prefServiceBridge = new PrefServiceBridge();
+        prefServiceBridge.setInteger(PREF, value);
+
+        verify(mNativeMock).setInteger(eq(PREF), eq(value));
+    }
+
+    @Test
+    public void testGetString() {
+        String expected = "foo";
+
+        PrefServiceBridge prefServiceBridge = new PrefServiceBridge();
+        doReturn(expected).when(mNativeMock).getString(PREF);
+
+        assertEquals(expected, prefServiceBridge.getString(PREF));
+    }
+
+    @Test
+    public void testSetString() {
+        String value = "bar";
+
+        PrefServiceBridge prefServiceBridge = new PrefServiceBridge();
+        prefServiceBridge.setString(PREF, value);
+
+        verify(mNativeMock).setString(eq(PREF), eq(value));
+    }
+
+    @Test
+    public void testIsManaged() {
+        boolean expected = true;
+
+        PrefServiceBridge prefServiceBridge = new PrefServiceBridge();
+        doReturn(expected).when(mNativeMock).isManagedPreference(PREF);
+
+        assertEquals(expected, prefServiceBridge.isManagedPreference(PREF));
+    }
+}
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 71080e2..527e35c0 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -2824,7 +2824,7 @@
     Use metered connection
   </message>
   <message name="IDS_UPDATE_REQUIRED_SCREEN_NO_NETWORK_MESSAGE" desc="The message on the dialog shown to the user in Chrome OS before forced update is attempted if the Chrome OS device is not connected to a network.">
-    <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to connect to Wi-Fi now and download an update. The update will download automatically when you connect to the internet.
+    <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to connect to Wi-Fi now and download an update.
   </message>
   <message name="IDS_UPDATE_REQUIRED_SCREEN_OPEN_NETWORK_SETTINGS" desc="Label for network configuration button on the update required dialog on the login screen to open network settings so that the user can connect to a network.">
     Open network settings
diff --git a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_SCREEN_NO_NETWORK_MESSAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_SCREEN_NO_NETWORK_MESSAGE.png.sha1
new file mode 100644
index 0000000..7603f6b0
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_SCREEN_NO_NETWORK_MESSAGE.png.sha1
@@ -0,0 +1 @@
+ac79ba6f1aaaf62f545c3cac72469d40bbb67016
\ No newline at end of file
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 4fa34571..4b6b685 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -1145,6 +1145,16 @@
 
       </if>
 
+      <!-- Profile Picker -->
+      <if expr="not chromeos and not is_android">
+        <message name="IDS_PROFILE_PICKER_MAIN_VIEW_TITLE" desc="Profile picker main view title">
+          Pick your Chromium Space
+        </message>
+        <message name="IDS_PROFILE_PICKER_MAIN_VIEW_SUBTITLE" desc="Profile picker main view subtitle">
+          Use Chromium Spaces to keep your browsing organized on this device
+        </message>
+      </if>
+
     </messages>
   </release>
 </grit>
diff --git a/chrome/app/chromium_strings_grd/IDS_PROFILE_PICKER_MAIN_VIEW_SUBTITLE.png.sha1 b/chrome/app/chromium_strings_grd/IDS_PROFILE_PICKER_MAIN_VIEW_SUBTITLE.png.sha1
new file mode 100644
index 0000000..cbd5f67
--- /dev/null
+++ b/chrome/app/chromium_strings_grd/IDS_PROFILE_PICKER_MAIN_VIEW_SUBTITLE.png.sha1
@@ -0,0 +1 @@
+c3d7fda79021a7aced9e44521ec13b3d450f9e59
\ No newline at end of file
diff --git a/chrome/app/chromium_strings_grd/IDS_PROFILE_PICKER_MAIN_VIEW_TITLE.png.sha1 b/chrome/app/chromium_strings_grd/IDS_PROFILE_PICKER_MAIN_VIEW_TITLE.png.sha1
new file mode 100644
index 0000000..cbd5f67
--- /dev/null
+++ b/chrome/app/chromium_strings_grd/IDS_PROFILE_PICKER_MAIN_VIEW_TITLE.png.sha1
@@ -0,0 +1 @@
+c3d7fda79021a7aced9e44521ec13b3d450f9e59
\ No newline at end of file
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index c9a3fa55..66d9128 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -1160,6 +1160,17 @@
          Your parent has turned off "Permissions for sites, apps and extensions" for Chrome. Enabling this <ph name="EXTENSION_TYPE_PARAMETER">$1<ex>extension</ex></ph> is not allowed.
         </message>
       </if>
+
+      <!-- Profile Picker -->
+      <if expr="not chromeos and not is_android">
+        <message name="IDS_PROFILE_PICKER_MAIN_VIEW_TITLE" desc="Profile picker main view title">
+          Pick your Chrome Space
+        </message>
+        <message name="IDS_PROFILE_PICKER_MAIN_VIEW_SUBTITLE" desc="Profile picker main view subtitle">
+          Use Chrome Spaces to keep your browsing organized on this device
+        </message>
+      </if>
+
     </messages>
   </release>
 </grit>
diff --git a/chrome/app/google_chrome_strings_grd/IDS_PROFILE_PICKER_MAIN_VIEW_SUBTITLE.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_PROFILE_PICKER_MAIN_VIEW_SUBTITLE.png.sha1
new file mode 100644
index 0000000..cbd5f67
--- /dev/null
+++ b/chrome/app/google_chrome_strings_grd/IDS_PROFILE_PICKER_MAIN_VIEW_SUBTITLE.png.sha1
@@ -0,0 +1 @@
+c3d7fda79021a7aced9e44521ec13b3d450f9e59
\ No newline at end of file
diff --git a/chrome/app/google_chrome_strings_grd/IDS_PROFILE_PICKER_MAIN_VIEW_TITLE.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_PROFILE_PICKER_MAIN_VIEW_TITLE.png.sha1
new file mode 100644
index 0000000..cbd5f67
--- /dev/null
+++ b/chrome/app/google_chrome_strings_grd/IDS_PROFILE_PICKER_MAIN_VIEW_TITLE.png.sha1
@@ -0,0 +1 @@
+c3d7fda79021a7aced9e44521ec13b3d450f9e59
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index c7f3e14..1a430439 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2501,6 +2501,7 @@
       "android/preferences/cookie_controls_service_bridge.h",
       "android/preferences/pref_change_registrar_android.cc",
       "android/preferences/pref_change_registrar_android.h",
+      "android/preferences/pref_service_bridge.cc",
       "android/preferences/privacy_preferences_manager.cc",
       "android/profile_key_startup_accessor.cc",
       "android/profile_key_startup_accessor.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index e6bfcd6..1fcbc991 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -4861,7 +4861,7 @@
 
     {"enable-skia-renderer", flag_descriptions::kSkiaRendererName,
      flag_descriptions::kSkiaRendererDescription,
-     kOsLinux | kOsWin | kOsAndroid,
+     kOsLinux | kOsWin | kOsAndroid | kOsMac,
      FEATURE_VALUE_TYPE(features::kUseSkiaRenderer)},
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/android/bookmarks/partner_bookmarks_shim_unittest.cc b/chrome/browser/android/bookmarks/partner_bookmarks_shim_unittest.cc
index 8e168b53..87bd7f5 100644
--- a/chrome/browser/android/bookmarks/partner_bookmarks_shim_unittest.cc
+++ b/chrome/browser/android/bookmarks/partner_bookmarks_shim_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/android/bookmarks/partner_bookmarks_reader.h"
+#include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/bookmarks/test/bookmark_test_helpers.h"
 #include "content/public/browser/browser_thread.h"
@@ -43,8 +44,11 @@
  protected:
   // testing::Test
   void SetUp() override {
-    profile_.reset(new TestingProfile());
-    profile_->CreateBookmarkModel(true);
+    TestingProfile::Builder profile_builder;
+    profile_builder.AddTestingFactory(
+        BookmarkModelFactory::GetInstance(),
+        BookmarkModelFactory::GetDefaultFactory());
+    profile_ = profile_builder.Build();
   }
 
   void TearDown() override {
diff --git a/chrome/browser/android/preferences/OWNERS b/chrome/browser/android/preferences/OWNERS
index b54eef54..2299408 100644
--- a/chrome/browser/android/preferences/OWNERS
+++ b/chrome/browser/android/preferences/OWNERS
@@ -1,4 +1,5 @@
-file://components/prefs/android/OWNERS
+twellington@chromium.org
+chouinard@chromium.org
 
 per-file cookie_controls*=dullweber@chromium.org
 
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc
new file mode 100644
index 0000000..727e9b1
--- /dev/null
+++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -0,0 +1,90 @@
+// 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 <jni.h>
+
+#include <string>
+
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "chrome/browser/preferences/jni_headers/PrefServiceBridge_jni.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "components/prefs/pref_service.h"
+
+namespace {
+
+using base::android::JavaParamRef;
+
+PrefService* GetPrefService() {
+  return ProfileManager::GetActiveUserProfile()
+      ->GetOriginalProfile()
+      ->GetPrefs();
+}
+
+}  // namespace
+
+// ----------------------------------------------------------------------------
+// Native JNI methods
+// ----------------------------------------------------------------------------
+
+static void JNI_PrefServiceBridge_ClearPref(
+    JNIEnv* env,
+    const JavaParamRef<jstring>& j_preference) {
+  GetPrefService()->ClearPref(
+      base::android::ConvertJavaStringToUTF8(env, j_preference));
+}
+
+static jboolean JNI_PrefServiceBridge_GetBoolean(
+    JNIEnv* env,
+    const JavaParamRef<jstring>& j_preference) {
+  return GetPrefService()->GetBoolean(
+      base::android::ConvertJavaStringToUTF8(env, j_preference));
+}
+
+static void JNI_PrefServiceBridge_SetBoolean(
+    JNIEnv* env,
+    const JavaParamRef<jstring>& j_preference,
+    const jboolean j_value) {
+  GetPrefService()->SetBoolean(
+      base::android::ConvertJavaStringToUTF8(env, j_preference), j_value);
+}
+
+static jint JNI_PrefServiceBridge_GetInteger(
+    JNIEnv* env,
+    const JavaParamRef<jstring>& j_preference) {
+  return GetPrefService()->GetInteger(
+      base::android::ConvertJavaStringToUTF8(env, j_preference));
+}
+
+static void JNI_PrefServiceBridge_SetInteger(
+    JNIEnv* env,
+    const JavaParamRef<jstring>& j_preference,
+    const jint j_value) {
+  GetPrefService()->SetInteger(
+      base::android::ConvertJavaStringToUTF8(env, j_preference), j_value);
+}
+
+static base::android::ScopedJavaLocalRef<jstring>
+JNI_PrefServiceBridge_GetString(JNIEnv* env,
+                                const JavaParamRef<jstring>& j_preference) {
+  return base::android::ConvertUTF8ToJavaString(
+      env, GetPrefService()->GetString(
+               base::android::ConvertJavaStringToUTF8(env, j_preference)));
+}
+
+static void JNI_PrefServiceBridge_SetString(
+    JNIEnv* env,
+    const JavaParamRef<jstring>& j_preference,
+    const base::android::JavaParamRef<jstring>& j_value) {
+  GetPrefService()->SetString(
+      base::android::ConvertJavaStringToUTF8(env, j_preference),
+      base::android::ConvertJavaStringToUTF8(env, j_value));
+}
+
+static jboolean JNI_PrefServiceBridge_IsManagedPreference(
+    JNIEnv* env,
+    const JavaParamRef<jstring>& j_preference) {
+  return GetPrefService()->IsManagedPreference(
+      base::android::ConvertJavaStringToUTF8(env, j_preference));
+}
diff --git a/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc b/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
index 5fd0e32..3d258c24 100644
--- a/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
@@ -154,13 +154,19 @@
 TEST_F(BookmarkHTMLWriterTest, Test) {
   content::BrowserTaskEnvironment task_environment;
 
-  TestingProfile profile;
-  ASSERT_TRUE(profile.CreateHistoryService(true, false));
-  profile.BlockUntilHistoryProcessesPendingRequests();
-  profile.CreateFaviconService();
-  profile.CreateBookmarkModel(true);
+  TestingProfile::Builder profile_builder;
+  profile_builder.AddTestingFactory(BookmarkModelFactory::GetInstance(),
+                                    BookmarkModelFactory::GetDefaultFactory());
+  profile_builder.AddTestingFactory(FaviconServiceFactory::GetInstance(),
+                                    FaviconServiceFactory::GetDefaultFactory());
+  profile_builder.AddTestingFactory(HistoryServiceFactory::GetInstance(),
+                                    HistoryServiceFactory::GetDefaultFactory());
 
-  BookmarkModel* model = BookmarkModelFactory::GetForBrowserContext(&profile);
+  std::unique_ptr<TestingProfile> profile = profile_builder.Build();
+  profile->BlockUntilHistoryProcessesPendingRequests();
+
+  BookmarkModel* model =
+      BookmarkModelFactory::GetForBrowserContext(profile.get());
   bookmarks::test::WaitForBookmarkModelToLoad(model);
 
   // Create test PNG representing favicon for url1.
@@ -208,10 +214,10 @@
   const BookmarkNode* f1 = model->AddFolder(
       model->bookmark_bar_node(), 0, f1_title);
   model->AddURL(f1, 0, url1_title, url1, nullptr, t1);
-  HistoryServiceFactory::GetForProfile(&profile,
+  HistoryServiceFactory::GetForProfile(profile.get(),
                                        ServiceAccessType::EXPLICIT_ACCESS)
       ->AddPage(url1, base::Time::Now(), history::SOURCE_BROWSED);
-  FaviconServiceFactory::GetForProfile(&profile,
+  FaviconServiceFactory::GetForProfile(profile.get(),
                                        ServiceAccessType::EXPLICIT_ACCESS)
       ->SetFavicons({url1}, url1_favicon, favicon_base::IconType::kFavicon,
                     gfx::Image::CreateFrom1xBitmap(bitmap));
@@ -233,7 +239,7 @@
 
   // Write to a temp file.
   BookmarksObserver observer(&run_loop);
-  bookmark_html_writer::WriteBookmarks(&profile, path_, &observer);
+  bookmark_html_writer::WriteBookmarks(profile.get(), path_, &observer);
   run_loop.Run();
   if (HasFailure()) {
     // WriteBookmarks has failed, no point in trying to read the file.
@@ -241,7 +247,7 @@
   }
 
   // Clear favicon so that it would be read from file.
-  FaviconServiceFactory::GetForProfile(&profile,
+  FaviconServiceFactory::GetForProfile(profile.get(),
                                        ServiceAccessType::EXPLICIT_ACCESS)
       ->SetFavicons({url1}, url1_favicon, favicon_base::IconType::kFavicon,
                     gfx::Image());
diff --git a/chrome/browser/bookmarks/bookmark_model_factory.cc b/chrome/browser/bookmarks/bookmark_model_factory.cc
index 6aff6bc..7bbee08 100644
--- a/chrome/browser/bookmarks/bookmark_model_factory.cc
+++ b/chrome/browser/bookmarks/bookmark_model_factory.cc
@@ -28,8 +28,35 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 
+namespace {
+
 using bookmarks::BookmarkModel;
 
+std::unique_ptr<KeyedService> BuildBookmarkModel(
+    content::BrowserContext* context,
+    const scoped_refptr<base::SequencedTaskRunner>& io_task_runner) {
+  Profile* profile = Profile::FromBrowserContext(context);
+  auto bookmark_model =
+      std::make_unique<BookmarkModel>(std::make_unique<ChromeBookmarkClient>(
+          profile, ManagedBookmarkServiceFactory::GetForProfile(profile),
+          BookmarkSyncServiceFactory::GetForProfile(profile)));
+  bookmark_model->Load(profile->GetPrefs(), profile->GetPath(), io_task_runner,
+                       content::GetUIThreadTaskRunner({}));
+  BookmarkUndoServiceFactory::GetForProfile(profile)->Start(
+      bookmark_model.get());
+  return bookmark_model;
+}
+
+std::unique_ptr<KeyedService> BuildBookmarkModelForTesting(
+    content::BrowserContext* context) {
+  Profile* profile = Profile::FromBrowserContext(context);
+  // During testing, avoid deferring I/O tasks and having to explicitly
+  // invoke StartupTaskRunnerService:: StartDeferredTaskRunners().
+  return BuildBookmarkModel(context, profile->GetIOTaskRunner());
+}
+
+}  // namespace
+
 // static
 BookmarkModel* BookmarkModelFactory::GetForBrowserContext(
     content::BrowserContext* context) {
@@ -49,6 +76,12 @@
   return base::Singleton<BookmarkModelFactory>::get();
 }
 
+// static
+BrowserContextKeyedServiceFactory::TestingFactory
+BookmarkModelFactory::GetDefaultFactory() {
+  return base::BindRepeating(&BuildBookmarkModelForTesting);
+}
+
 BookmarkModelFactory::BookmarkModelFactory()
     : BrowserContextKeyedServiceFactory(
         "BookmarkModel",
@@ -65,17 +98,10 @@
 KeyedService* BookmarkModelFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
-  BookmarkModel* bookmark_model =
-      new BookmarkModel(std::make_unique<ChromeBookmarkClient>(
-          profile, ManagedBookmarkServiceFactory::GetForProfile(profile),
-          BookmarkSyncServiceFactory::GetForProfile(profile)));
-  bookmark_model->Load(profile->GetPrefs(), profile->GetPath(),
-                       StartupTaskRunnerServiceFactory::GetForProfile(profile)
-                           ->GetBookmarkTaskRunner(),
-                       content::GetUIThreadTaskRunner({}));
-  BookmarkUndoServiceFactory::GetForProfile(profile)->Start(bookmark_model);
-
-  return bookmark_model;
+  return BuildBookmarkModel(
+             context, StartupTaskRunnerServiceFactory::GetForProfile(profile)
+                          ->GetBookmarkTaskRunner())
+      .release();
 }
 
 void BookmarkModelFactory::RegisterProfilePrefs(
diff --git a/chrome/browser/bookmarks/bookmark_model_factory.h b/chrome/browser/bookmarks/bookmark_model_factory.h
index bd388e3..55af05f 100644
--- a/chrome/browser/bookmarks/bookmark_model_factory.h
+++ b/chrome/browser/bookmarks/bookmark_model_factory.h
@@ -28,6 +28,9 @@
 
   static BookmarkModelFactory* GetInstance();
 
+  // Returns the default factory, useful in tests where it's null by default.
+  static TestingFactory GetDefaultFactory();
+
  private:
   friend struct base::DefaultSingletonTraits<BookmarkModelFactory>;
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 506a6f7..9819d8d 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -169,7 +169,6 @@
 #include "chrome/common/logging_chrome.h"
 #include "chrome/common/pepper_permission_util.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/common/prerender_url_loader_throttle.h"
 #include "chrome/common/profiler/stack_sampling_configuration.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/renderer_configuration.mojom.h"
@@ -226,6 +225,7 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
+#include "components/prerender//common/prerender_url_loader_throttle.h"
 #include "components/prerender/common/prerender_final_status.h"
 #include "components/prerender/common/prerender_types.mojom.h"
 #include "components/prerender/common/prerender_util.h"
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.cc
index 77a17d9..9a21d841 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.cc
@@ -9,7 +9,9 @@
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
+#include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/cryptohome/cryptohome_client.h"
@@ -207,5 +209,17 @@
   return cert_list[0];
 }
 
+platform_keys::PlatformKeysService* GetPlatformKeysService(CertScope scope,
+                                                           Profile* profile) {
+  switch (scope) {
+    case CertScope::kUser:
+      return platform_keys::PlatformKeysServiceFactory::GetForBrowserContext(
+          profile);
+    case CertScope::kDevice:
+      return platform_keys::PlatformKeysServiceFactory::GetInstance()
+          ->GetDeviceWideService();
+  }
+}
+
 }  // namespace cert_provisioning
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.h b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.h
index 9d2a6ad6..b497dc1 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.h
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.h
@@ -21,6 +21,11 @@
 class Profile;
 
 namespace chromeos {
+
+namespace platform_keys {
+class PlatformKeysService;
+}  // namespace platform_keys
+
 namespace cert_provisioning {
 
 // Used for both DeleteVaKey and DeleteVaKeysByPrefix
@@ -131,6 +136,16 @@
     const char* data,
     size_t length);
 
+// Returns the PlatformKeysService to be used.
+// If |scope| is CertScope::kDevice, |profile| is ignored and the
+// device-wide PlatformKeysService is returned.
+// If |scope| is CertScope::kUser, returns the service for |profile|.
+// The returned object is owned by the Profile (user-specific) or globally
+// (device-wide) and may only be used until it notifies its observers that it is
+// being shut down.
+platform_keys::PlatformKeysService* GetPlatformKeysService(CertScope scope,
+                                                           Profile* profile);
+
 }  // namespace cert_provisioning
 }  // namespace chromeos
 
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.cc
index ee9a443..51c18bd7 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.cc
@@ -105,7 +105,7 @@
   policy::CloudPolicyClient* cloud_policy_client =
       GetCloudPolicyClientForUser(profile);
   platform_keys::PlatformKeysService* platform_keys_service =
-      platform_keys::PlatformKeysServiceFactory::GetForBrowserContext(profile);
+      GetPlatformKeysService(CertScope::kUser, profile);
   NetworkStateHandler* network_state_handler = GetNetworkStateHandler();
 
   if (!profile || !pref_service || !cloud_policy_client ||
@@ -130,7 +130,7 @@
   policy::CloudPolicyClient* cloud_policy_client =
       GetCloudPolicyClientForDevice();
   platform_keys::PlatformKeysService* platform_keys_service =
-      platform_keys::PlatformKeysServiceFactory::GetForBrowserContext(profile);
+      GetPlatformKeysService(CertScope::kDevice, profile);
   NetworkStateHandler* network_state_handler = GetNetworkStateHandler();
 
   if (!profile || !pref_service || !cloud_policy_client ||
@@ -173,6 +173,8 @@
   pref_name_ = GetPrefNameForCertProfiles(cert_scope);
   CHECK(pref_name_);
 
+  scoped_platform_keys_service_observer_.Add(platform_keys_service_);
+
   network_state_handler_->AddObserver(this, FROM_HERE);
 
   ScheduleInitialUpdate();
@@ -238,6 +240,10 @@
 
 void CertProvisioningSchedulerImpl::DeleteCertsWithoutPolicy() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  // No-op if the PlatformKeysService has already been shut down.
+  if (!platform_keys_service_) {
+    return;
+  }
 
   base::flat_set<CertProfileId> cert_profile_ids_to_keep;
   {
@@ -391,6 +397,11 @@
     std::vector<CertProfile> profiles) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
+  // No-op if the PlatformKeysService has already been shut down.
+  if (!platform_keys_service_) {
+    return;
+  }
+
   if (!MaybeWaitForInternetConnection()) {
     return;
   }
@@ -677,6 +688,23 @@
   failed_cert_profiles_[worker.GetCertProfile().profile_id] = std::move(info);
 }
 
+void CertProvisioningSchedulerImpl::OnPlatformKeysServiceShutDown() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  // The |platform_keys_service_| will only return errors going forward, so
+  // stop using it. Shutdown all workers, as if this CertProvisioningScheduler
+  // was destroyed, and stop pending tasks that may depend on
+  // |platform_keys_service_|.
+  workers_.clear();
+  certs_with_ids_getter_.Cancel();
+  cert_deleter_.Cancel();
+  pref_change_registrar_.RemoveAll();
+  weak_factory_.InvalidateWeakPtrs();
+
+  scoped_platform_keys_service_observer_.RemoveAll();
+  platform_keys_service_ = nullptr;
+}
+
 void CertProvisioningSchedulerImpl::CancelWorkersWithoutPolicy(
     const std::vector<CertProfile>& profiles) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.h b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.h
index 5fadcce6..d94b76c3 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.h
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.h
@@ -10,11 +10,13 @@
 #include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
 #include "base/memory/weak_ptr.h"
+#include "base/scoped_observer.h"
 #include "base/sequence_checker.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.h"
 #include "chrome/browser/chromeos/cert_provisioning/cert_provisioning_invalidator.h"
 #include "chrome/browser/chromeos/cert_provisioning/cert_provisioning_platform_keys_helpers.h"
+#include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
 #include "chromeos/network/network_state_handler_observer.h"
 #include "components/prefs/pref_change_registrar.h"
 
@@ -29,10 +31,6 @@
 
 class NetworkStateHandler;
 
-namespace platform_keys {
-class PlatformKeysService;
-}  // namespace platform_keys
-
 namespace cert_provisioning {
 
 class CertProvisioningWorker;
@@ -82,8 +80,10 @@
 // Should work on the UI thread because it interacts with PlatformKeysService
 // and some methods are called from the UI to populate certificate manager
 // settings page.
-class CertProvisioningSchedulerImpl : public CertProvisioningScheduler,
-                                      public NetworkStateHandlerObserver {
+class CertProvisioningSchedulerImpl
+    : public CertProvisioningScheduler,
+      public NetworkStateHandlerObserver,
+      public platform_keys::PlatformKeysServiceObserver {
  public:
   static std::unique_ptr<CertProvisioningScheduler>
   CreateUserCertProvisioningScheduler(Profile* profile);
@@ -167,11 +167,15 @@
 
   void UpdateFailedCertProfiles(const CertProvisioningWorker& worker);
 
+  // PlatformKeysServiceObserver
+  void OnPlatformKeysServiceShutDown() override;
+
   CertScope cert_scope_ = CertScope::kUser;
   Profile* profile_ = nullptr;
   PrefService* pref_service_ = nullptr;
   const char* pref_name_ = nullptr;
   policy::CloudPolicyClient* cloud_policy_client_ = nullptr;
+  // |platform_keys_service_| can be nullptr if it has been shut down.
   platform_keys::PlatformKeysService* platform_keys_service_ = nullptr;
   NetworkStateHandler* network_state_handler_ = nullptr;
   PrefChangeRegistrar pref_change_registrar_;
@@ -197,6 +201,10 @@
   CertDeleter cert_deleter_;
   std::unique_ptr<CertProvisioningInvalidatorFactory> invalidator_factory_;
 
+  ScopedObserver<platform_keys::PlatformKeysService,
+                 platform_keys::PlatformKeysServiceObserver>
+      scoped_platform_keys_service_observer_{this};
+
   base::WeakPtrFactory<CertProvisioningSchedulerImpl> weak_factory_{this};
 };
 
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler_unittest.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler_unittest.cc
index b6e8c30..22a65c3 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler_unittest.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler_unittest.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/chromeos/cert_provisioning/mock_cert_provisioning_worker.h"
 #include "chrome/browser/chromeos/platform_keys/mock_platform_keys_service.h"
 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
-#include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/network/network_state_test_helper.h"
 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
@@ -33,6 +32,7 @@
 using testing::Mock;
 using testing::Return;
 using testing::ReturnRef;
+using testing::SaveArg;
 using testing::StrictMock;
 
 namespace chromeos {
@@ -900,6 +900,56 @@
   ASSERT_EQ(scheduler.GetWorkers().size(), 1U);
 }
 
+TEST_F(CertProvisioningSchedulerTest, PlatformKeysServiceShutDown) {
+  CertScope kCertScope = CertScope::kDevice;
+
+  platform_keys::PlatformKeysServiceObserver* observer = nullptr;
+  EXPECT_CALL(platform_keys_service_, AddObserver(_))
+      .WillOnce(SaveArg<0>(&observer));
+  CertProvisioningSchedulerImpl scheduler(
+      kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
+      &platform_keys_service_,
+      network_state_test_helper_.network_state_handler(),
+      MakeFakeInvalidationFactory());
+
+  ASSERT_TRUE(observer);
+
+  // Add 1 certificate profile to the policy.
+  base::Value config = ParseJson(
+      R"([{"name": "Certificate Profile 1",
+           "cert_profile_id":"cert_profile_id_1",
+           "policy_version":"cert_profile_version_1",
+           "key_algorithm":"rsa" }])");
+  pref_service_.Set(prefs::kRequiredClientCertificateForDevice, config);
+
+  // Same as in the policy.
+  const char kCertProfileId[] = "cert_profile_id_1";
+  const char kCertProfileVersion[] = "cert_profile_version_1";
+  CertProfile cert_profile{kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod};
+
+  MockCertProvisioningWorker* worker =
+      mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
+  worker->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
+                          cert_profile);
+  scheduler.UpdateAllCerts();
+
+  // Now 1 worker should be created.
+  EXPECT_EQ(scheduler.GetWorkers().size(), 1U);
+
+  // PlatformKeysService notifies that it is shutting down.
+  EXPECT_CALL(platform_keys_service_, RemoveObserver(observer));
+  observer->OnPlatformKeysServiceShutDown();
+
+  // The worker should be deleted.
+  EXPECT_EQ(scheduler.GetWorkers().size(), 0U);
+
+  // Check one more time that scheduler doesn't create new workers after
+  // PlatformKeysService has been shut down (the factory will fail on an attempt
+  // to do so).
+  scheduler.UpdateAllCerts();
+}
+
 }  // namespace
 }  // namespace cert_provisioning
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker.cc
index 0c2bfbdc..bd00ee03 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker.cc
@@ -187,8 +187,7 @@
       cloud_policy_client_(cloud_policy_client),
       invalidator_(std::move(invalidator)) {
   CHECK(profile);
-  platform_keys_service_ =
-      platform_keys::PlatformKeysServiceFactory::GetForBrowserContext(profile);
+  platform_keys_service_ = GetPlatformKeysService(cert_scope, profile);
   CHECK(platform_keys_service_);
 
   CHECK(pref_service);
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker.h b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker.h
index d4c8c32..3bd6b29 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker.h
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker.h
@@ -254,6 +254,10 @@
   // because of it).
   static constexpr int kVersion = 1;
 
+  // Unowned PlatformKeysService. Note that the CertProvisioningWorker does not
+  // observe the PlatformKeysService for shutdown events. Instead, it relies on
+  // the CertProvisioningScheduler to destroy all CertProvisioningWorker
+  // instances when the corresponding PlatformKeysService is shutting down.
   platform_keys::PlatformKeysService* platform_keys_service_ = nullptr;
   std::unique_ptr<attestation::TpmChallengeKeySubtle>
       tpm_challenge_key_subtle_impl_;
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker_unittest.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker_unittest.cc
index 1d63f26..5164369 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker_unittest.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker_unittest.cc
@@ -344,6 +344,9 @@
                     base::BindRepeating(
                         &platform_keys::BuildMockPlatformKeysService)));
     ASSERT_TRUE(platform_keys_service_);
+    platform_keys::PlatformKeysServiceFactory::GetInstance()
+        ->SetDeviceWideServiceForTesting(platform_keys_service_);
+
     // Only explicitly expected removals are allowed.
     EXPECT_CALL(*platform_keys_service_, RemoveCertificate).Times(0);
     EXPECT_CALL(*platform_keys_service_, RemoveKey).Times(0);
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc b/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
index c93e161..7032c75 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
@@ -741,8 +741,7 @@
 
 // Zero touch with attestation authentication fail. Attestation fails because we
 // send empty cert request. Should switch to interactive authentication.
-IN_PROC_BROWSER_TEST_F(InitialEnrollmentTest,
-                       DISABLED_ZeroTouchForcedAttestationFail) {
+IN_PROC_BROWSER_TEST_F(InitialEnrollmentTest, ZeroTouchForcedAttestationFail) {
   auto initial_enrollment =
       enterprise_management::DeviceInitialEnrollmentStateResponse::
           INITIAL_ENROLLMENT_MODE_ZERO_TOUCH_ENFORCED;
diff --git a/chrome/browser/chromeos/platform_keys/mock_platform_keys_service.h b/chrome/browser/chromeos/platform_keys/mock_platform_keys_service.h
index 3499fd0..bb635f7 100644
--- a/chrome/browser/chromeos/platform_keys/mock_platform_keys_service.h
+++ b/chrome/browser/chromeos/platform_keys/mock_platform_keys_service.h
@@ -11,6 +11,10 @@
 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
+namespace content {
+class BrowserContext;
+}
+
 namespace chromeos {
 namespace platform_keys {
 
@@ -22,6 +26,16 @@
   ~MockPlatformKeysService() override;
 
   MOCK_METHOD(void,
+              AddObserver,
+              (PlatformKeysServiceObserver * observer),
+              (override));
+
+  MOCK_METHOD(void,
+              RemoveObserver,
+              (PlatformKeysServiceObserver * observer),
+              (override));
+
+  MOCK_METHOD(void,
               GenerateRSAKey,
               (TokenId token_id,
                unsigned int modulus_length_bits,
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
index 6daf920d..e212b24 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
@@ -5,12 +5,14 @@
 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
 
 #include <map>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/location.h"
 #include "base/task/post_task.h"
 #include "base/task/thread_pool.h"
+#include "content/public/browser/browser_thread.h"
 #include "net/base/hash_value.h"
 #include "net/cert/x509_certificate.h"
 
@@ -75,14 +77,65 @@
 
 ClientCertificateRequest::~ClientCertificateRequest() = default;
 
+// =============== PlatformKeysServiceImplDelegate =============================
+
+PlatformKeysServiceImplDelegate::PlatformKeysServiceImplDelegate() = default;
+
+PlatformKeysServiceImplDelegate::~PlatformKeysServiceImplDelegate() {
+  ShutDown();
+}
+
+void PlatformKeysServiceImplDelegate::SetOnShutdownCallback(
+    base::OnceClosure on_shutdown_callback) {
+  DCHECK(!shut_down_);
+  DCHECK(!on_shutdown_callback_);
+  on_shutdown_callback_ = std::move(on_shutdown_callback);
+}
+
+bool PlatformKeysServiceImplDelegate::IsShutDown() const {
+  return shut_down_;
+}
+
+void PlatformKeysServiceImplDelegate::ShutDown() {
+  if (shut_down_)
+    return;
+
+  shut_down_ = true;
+  if (on_shutdown_callback_)
+    std::move(on_shutdown_callback_).Run();
+}
+
 // =================== PlatformKeysServiceImpl =================================
 
 PlatformKeysServiceImpl::PlatformKeysServiceImpl(
-    content::BrowserContext* context)
-    : browser_context_(context) {}
+    std::unique_ptr<PlatformKeysServiceImplDelegate> delegate)
+    : delegate_(std::move(delegate)) {
+  // base::Unretained is OK because |delegate_| is owned by this and can
+  // only call the callback before it is destroyed.
+  delegate_->SetOnShutdownCallback(base::BindOnce(
+      &PlatformKeysServiceImpl::OnDelegateShutDown, base::Unretained(this)));
+}
 
 PlatformKeysServiceImpl::~PlatformKeysServiceImpl() = default;
 
+void PlatformKeysServiceImpl::AddObserver(
+    PlatformKeysServiceObserver* observer) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  observers_.AddObserver(observer);
+}
+
+void PlatformKeysServiceImpl::RemoveObserver(
+    PlatformKeysServiceObserver* observer) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  observers_.RemoveObserver(observer);
+}
+
+void PlatformKeysServiceImpl::OnDelegateShutDown() {
+  for (auto& observer : observers_) {
+    observer.OnPlatformKeysServiceShutDown();
+  }
+}
+
 // The rest of the methods - the NSS-specific part of the implementation -
 // resides in the platform_keys_service_nss.cc file.
 
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.h b/chrome/browser/chromeos/platform_keys/platform_keys_service.h
index 21bbf9e..0cf42a0 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service.h
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.h
@@ -11,16 +11,19 @@
 #include <string>
 #include <vector>
 
-#include "base/callback_forward.h"
+#include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "base/optional.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "net/cert/x509_certificate.h"
 
-namespace content {
-class BrowserContext;
-}
+namespace net {
+class NSSCertDatabase;
+class ClientCertStore;
+}  // namespace net
 
 namespace chromeos {
 namespace platform_keys {
@@ -178,10 +181,27 @@
     base::OnceCallback<void(const base::Optional<std::string>& attribute_value,
                             const std::string& error_message)>;
 
+// An observer that gets notified when the PlatformKeysService is being shut
+// down.
+class PlatformKeysServiceObserver : public base::CheckedObserver {
+ public:
+  // Called when the PlatformKeysService is being shut down.
+  // It may not be used after this call - any usage except for removing the
+  // observer will DCHECK.
+  virtual void OnPlatformKeysServiceShutDown() = 0;
+};
+
 // Functions of this class shouldn't be called directly from the context of
 // an extension. Instead use ExtensionPlatformKeysService which enforces
 // restrictions upon extensions.
 // All public methods of this class should be called on the UI thread.
+// When the underlying key store is not available anymore, a PlatformKeysService
+// is shut down. Any function called after that will fail with an error.
+// For a Profile-specific PlatformKeysService, this will be when the Profile is
+// being destroyed.
+// For a device-wide PlatformKeysService, this will be at some point during
+// chrome shut down.
+// Use AddObserver to get a notification when the service shuts down.
 class PlatformKeysService : public KeyedService {
  public:
   PlatformKeysService() = default;
@@ -189,6 +209,12 @@
   PlatformKeysService& operator=(const PlatformKeysService&) = delete;
   ~PlatformKeysService() override = default;
 
+  // Adds |observer| which will be notified when this service is being shut
+  // down.
+  virtual void AddObserver(PlatformKeysServiceObserver* observer) = 0;
+  // Removes a previously added |observer|.
+  virtual void RemoveObserver(PlatformKeysServiceObserver* observer) = 0;
+
   // Generates a RSA key pair with |modulus_length_bits|. |token_id| specifies
   // the token to store the key pair on. |callback| will be invoked with the
   // resulting public key
@@ -328,12 +354,55 @@
       const bool map_to_softoken_attrs_for_testing) = 0;
 };
 
+class PlatformKeysServiceImplDelegate {
+ public:
+  PlatformKeysServiceImplDelegate();
+  virtual ~PlatformKeysServiceImplDelegate();
+  PlatformKeysServiceImplDelegate(
+      const PlatformKeysServiceImplDelegate& other) = delete;
+  PlatformKeysServiceImplDelegate& operator=(
+      const PlatformKeysServiceImplDelegate& other) = delete;
+
+  // |on_shutdown_callback| will be called when the underlying key/certificate
+  // store is shut down. It is an error to call this twice, or after the
+  // delegate has been shut down.
+  void SetOnShutdownCallback(base::OnceClosure on_shutdown_callback);
+
+  // This callback is invoked by GetNSSCertDatabase.
+  using OnGotNSSCertDatabase = base::OnceCallback<void(net::NSSCertDatabase*)>;
+
+  // Retrieves the NSSCertDatabase that should be used for certificate
+  // operations. |callback| will be called on the thread that GetNSSCertDatabase
+  // has been called on.
+  virtual void GetNSSCertDatabase(OnGotNSSCertDatabase callback) = 0;
+
+  // Creates a ClientCertStore that should be used to list / operate on client
+  // certificates.
+  virtual std::unique_ptr<net::ClientCertStore> CreateClientCertStore() = 0;
+
+  bool IsShutDown() const;
+
+ protected:
+  void ShutDown();
+
+ private:
+  // A callback that should be called when the underlying key/certificate store
+  // is shut down.
+  base::OnceClosure on_shutdown_callback_;
+
+  // True if the underlying key/certificate store has already been shut down.
+  bool shut_down_ = false;
+};
+
 class PlatformKeysServiceImpl final : public PlatformKeysService {
  public:
-  explicit PlatformKeysServiceImpl(content::BrowserContext* context);
+  explicit PlatformKeysServiceImpl(
+      std::unique_ptr<PlatformKeysServiceImplDelegate> delegate);
   ~PlatformKeysServiceImpl() override;
 
   // PlatformKeysService
+  void AddObserver(PlatformKeysServiceObserver* observer) override;
+  void RemoveObserver(PlatformKeysServiceObserver* observer) override;
   void GenerateRSAKey(TokenId token_id,
                       unsigned int modulus_length_bits,
                       const GenerateKeyCallback& callback) override;
@@ -386,7 +455,11 @@
   bool IsSetMapToSoftokenAttrsForTesting();
 
  private:
-  content::BrowserContext* const browser_context_;
+  void OnDelegateShutDown();
+
+  std::unique_ptr<PlatformKeysServiceImplDelegate> const delegate_;
+  // List of observers that will be notified when the service is shut down.
+  base::ObserverList<PlatformKeysServiceObserver> observers_;
   bool map_to_softoken_attrs_for_testing_ = false;
   base::WeakPtrFactory<PlatformKeysServiceImpl> weak_factory_{this};
 };
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service_factory.cc b/chrome/browser/chromeos/platform_keys/platform_keys_service_factory.cc
index 796ee5b..0d1ae549 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service_factory.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service_factory.cc
@@ -4,14 +4,129 @@
 
 #include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h"
 
+#include "base/callback_helpers.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/singleton.h"
+#include "base/scoped_observer.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chrome/browser/chromeos/certificate_provider/certificate_provider.h"
+#include "chrome/browser/chromeos/net/client_cert_store_chromeos.h"
 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/chromeos/system_token_cert_db_initializer.h"
+#include "chrome/browser/net/nss_context.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/user_manager/user.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/resource_context.h"
+#include "net/cert/nss_cert_database.h"
 
 namespace chromeos {
 namespace platform_keys {
 
+namespace {
+
+// Invoked on the IO thread when a NSSCertDatabase is available, delegates back
+// to origin thread.
+void DidGetCertDbOnIoThread(
+    const scoped_refptr<base::SingleThreadTaskRunner>& origin_task_runner,
+    base::OnceCallback<void(net::NSSCertDatabase*)> callback,
+    net::NSSCertDatabase* cert_db) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+  origin_task_runner->PostTask(FROM_HERE,
+                               base::BindOnce(std::move(callback), cert_db));
+}
+
+// Retrieves the NSSCertDatabase for |context|. Must be called on the IO thread.
+void GetCertDatabaseOnIoThread(
+    const scoped_refptr<base::SingleThreadTaskRunner>& origin_task_runner,
+    PlatformKeysServiceImplDelegate::OnGotNSSCertDatabase callback,
+    content::ResourceContext* context) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+  base::RepeatingCallback<void(net::NSSCertDatabase*)> on_got_on_io_thread =
+      base::BindRepeating(&DidGetCertDbOnIoThread, origin_task_runner,
+                          base::AdaptCallbackForRepeating(std::move(callback)));
+  net::NSSCertDatabase* cert_db =
+      GetNSSCertDatabaseForResourceContext(context, on_got_on_io_thread);
+
+  if (cert_db)
+    on_got_on_io_thread.Run(cert_db);
+}
+
+class DelegateForUser : public PlatformKeysServiceImplDelegate {
+ public:
+  explicit DelegateForUser(content::BrowserContext* browser_context)
+      : browser_context_(browser_context) {}
+  ~DelegateForUser() override = default;
+
+  void GetNSSCertDatabase(OnGotNSSCertDatabase callback) override {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+    content::GetIOThreadTaskRunner({})->PostTask(
+        FROM_HERE,
+        base::BindOnce(&GetCertDatabaseOnIoThread,
+                       base::ThreadTaskRunnerHandle::Get(), std::move(callback),
+                       browser_context_->GetResourceContext()));
+  }
+
+  std::unique_ptr<net::ClientCertStore> CreateClientCertStore() override {
+    const user_manager::User* user =
+        chromeos::ProfileHelper::Get()->GetUserByProfile(
+            Profile::FromBrowserContext(browser_context_));
+
+    // Use the device-wide system key slot only if the user is affiliated on the
+    // device.
+    const bool use_system_key_slot = user->IsAffiliated();
+    return std::make_unique<ClientCertStoreChromeOS>(
+        nullptr,  // no additional provider
+        use_system_key_slot, user->username_hash(),
+        ClientCertStoreChromeOS::PasswordDelegateFactory());
+  }
+
+ private:
+  content::BrowserContext* browser_context_;
+};
+
+class DelegateForDevice : public PlatformKeysServiceImplDelegate,
+                          public SystemTokenCertDBObserver {
+ public:
+  DelegateForDevice() {
+    scoped_observer_.Add(SystemTokenCertDBInitializer::Get());
+  }
+
+  ~DelegateForDevice() override = default;
+
+  void GetNSSCertDatabase(OnGotNSSCertDatabase callback) override {
+    SystemTokenCertDBInitializer::Get()->GetSystemTokenCertDb(
+        std::move(callback));
+  }
+
+  std::unique_ptr<net::ClientCertStore> CreateClientCertStore() override {
+    return std::make_unique<ClientCertStoreChromeOS>(
+        nullptr,  // no additional provider
+        /*use_system_key_slot=*/true, /*username_hash=*/std::string(),
+        ClientCertStoreChromeOS::PasswordDelegateFactory());
+  }
+
+ private:
+  ScopedObserver<SystemTokenCertDBInitializer, SystemTokenCertDBObserver>
+      scoped_observer_{this};
+
+  // SystemTokenCertDBObserver:
+  void OnSystemTokenCertDBDestroyed() override {
+    scoped_observer_.RemoveAll();
+    ShutDown();
+  }
+};
+
+}  // namespace
+
 // static
 PlatformKeysService* PlatformKeysServiceFactory::GetForBrowserContext(
     content::BrowserContext* context) {
@@ -24,6 +139,23 @@
   return base::Singleton<PlatformKeysServiceFactory>::get();
 }
 
+// static
+PlatformKeysService* PlatformKeysServiceFactory::GetDeviceWideService() {
+  if (device_wide_service_for_testing_)
+    return device_wide_service_for_testing_;
+
+  if (!device_wide_service_) {
+    device_wide_service_ = std::make_unique<PlatformKeysServiceImpl>(
+        std::make_unique<DelegateForDevice>());
+  }
+  return device_wide_service_.get();
+}
+
+void PlatformKeysServiceFactory::SetDeviceWideServiceForTesting(
+    PlatformKeysService* device_wide_service_for_testing) {
+  device_wide_service_for_testing_ = device_wide_service_for_testing;
+}
+
 PlatformKeysServiceFactory::PlatformKeysServiceFactory()
     : BrowserContextKeyedServiceFactory(
           "PlatformKeysService",
@@ -33,7 +165,16 @@
 
 KeyedService* PlatformKeysServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
-  return new PlatformKeysServiceImpl(context);
+  std::unique_ptr<PlatformKeysServiceImplDelegate> delegate;
+  Profile* profile = Profile::FromBrowserContext(context);
+  if (ProfileHelper::IsSigninProfile(profile) ||
+      ProfileHelper::IsLockScreenAppProfile(profile)) {
+    delegate = std::make_unique<DelegateForDevice>();
+  } else {
+    delegate = std::make_unique<DelegateForUser>(context);
+  }
+
+  return new PlatformKeysServiceImpl(std::move(delegate));
 }
 
 content::BrowserContext* PlatformKeysServiceFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h b/chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h
index bd2902a..cf97e46 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h
@@ -25,6 +25,21 @@
 
   static PlatformKeysServiceFactory* GetInstance();
 
+  // Returns an instance of PlatformKeysService that allows operations on the
+  // device-wide key store and is not tied to a user.
+  // The lifetime of the returned service is tied to the
+  // PlatformKeysServiceFactory itself.
+  PlatformKeysService* GetDeviceWideService();
+
+  // When call with a nun-nullptr |device_wide_service_for_testing|, subsequent
+  // calls to GetDeviceWideService() will return the passed pointer.
+  // When called with nullptr, subsequent calls to GetDeviceWideService() will
+  // return the default device-wide PlatformKeysService again.
+  // The caller is responsible that this is called with nullptr before an object
+  // previously passed in is destroyed.
+  void SetDeviceWideServiceForTesting(
+      PlatformKeysService* device_wide_service_for_testing);
+
  private:
   friend struct base::DefaultSingletonTraits<PlatformKeysServiceFactory>;
 
@@ -39,6 +54,15 @@
       content::BrowserContext* context) const override;
   KeyedService* BuildServiceInstanceFor(
       content::BrowserContext* context) const override;
+
+  PlatformKeysService* GetOrCreateDeviceWideService();
+
+  // A PlatformKeysService that is not tied to a Profile/User and only has
+  // access to the system token.
+  // Initialized lazily.
+  std::unique_ptr<PlatformKeysService> device_wide_service_;
+
+  PlatformKeysService* device_wide_service_for_testing_ = nullptr;
 };
 }  // namespace platform_keys
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service_nss.cc b/chrome/browser/chromeos/platform_keys/platform_keys_service_nss.cc
index 86408df8..40d5b0e 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service_nss.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service_nss.cc
@@ -31,18 +31,12 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
-#include "chrome/browser/chromeos/certificate_provider/certificate_provider.h"
 #include "chrome/browser/chromeos/net/client_cert_store_chromeos.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/chromeos/system_token_cert_db_initializer.h"
 #include "chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.h"
-#include "chrome/browser/net/nss_context.h"
-#include "chrome/browser/profiles/profile.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_context.h"
 #include "crypto/nss_key_util.h"
 #include "crypto/openssl_util.h"
 #include "crypto/scoped_nss_types.h"
@@ -71,6 +65,7 @@
 const char kErrorKeyNotFound[] = "Key not found.";
 const char kErrorCertificateNotFound[] = "Certificate could not be found.";
 const char kErrorAlgorithmNotSupported[] = "Algorithm not supported.";
+const char kErrorShutDown[] = "Delegate shut down.";
 
 // The current maximal RSA modulus length that ChromeOS's TPM supports for key
 // generation.
@@ -116,17 +111,16 @@
   DISALLOW_COPY_AND_ASSIGN(NSSOperationState);
 };
 
-using GetCertDBCallback = base::Callback<void(net::NSSCertDatabase* cert_db)>;
+using GetCertDBCallback =
+    base::OnceCallback<void(net::NSSCertDatabase* cert_db)>;
 
-// Used by GetCertDatabaseOnIoThread and called back with the requested
-// NSSCertDatabase.
-// If |token_id| is provided, sets |slot_| of |state| accordingly and calls
-// |callback| if the database was successfully retrieved.
-void DidGetCertDbOnIoThread(base::Optional<TokenId> token_id,
-                            const GetCertDBCallback& callback,
+// Called on the UI thread with certificate database.
+void DidGetCertDbOnUiThread(base::Optional<TokenId> token_id,
+                            GetCertDBCallback callback,
                             NSSOperationState* state,
                             net::NSSCertDatabase* cert_db) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
   if (!cert_db) {
     LOG(ERROR) << "Couldn't get NSSCertDatabase.";
     state->OnError(FROM_HERE, kErrorInternal);
@@ -151,63 +145,25 @@
     }
   }
 
-  callback.Run(cert_db);
-}
-
-// Retrieves the NSSCertDatabase from |context| and, if |token_id| is provided,
-// the slot for |token_id|.
-// Must be called on the IO thread.
-void GetCertDatabaseOnIoThread(base::Optional<TokenId> token_id,
-                               const GetCertDBCallback& callback,
-                               content::ResourceContext* context,
-                               NSSOperationState* state) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  net::NSSCertDatabase* cert_db = GetNSSCertDatabaseForResourceContext(
-      context, base::Bind(&DidGetCertDbOnIoThread, token_id, callback, state));
-
-  if (cert_db)
-    DidGetCertDbOnIoThread(token_id, callback, state, cert_db);
-}
-
-// Called by SystemTokenCertDBInitializer on the UI thread with the system token
-// certificate database when it is initialized.
-void DidGetSystemTokenCertDbOnUiThread(base::Optional<TokenId> token_id,
-                                       const GetCertDBCallback& callback,
-                                       NSSOperationState* state,
-                                       net::NSSCertDatabase* cert_db) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
   // Sets |slot_| of |state| accordingly and calls |callback| on the IO thread
   // if the database was successfully retrieved.
   content::GetIOThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(&DidGetCertDbOnIoThread, token_id, callback,
-                                state, cert_db));
+      FROM_HERE, base::BindOnce(std::move(callback), cert_db));
 }
 
-// Asynchronously fetches the NSSCertDatabase for |browser_context| and, if
-// |token_id| is provided, the slot for |token_id|. Stores the slot in |state|
+// Asynchronously fetches the NSSCertDatabase using |delegate| and, if
+// |token_id| is not empty, the slot for |token_id|. Stores the slot in |state|
 // and passes the database to |callback|. Will run |callback| on the IO thread.
 // TODO(omorsi): Introduce timeout for retrieving certificate database in
 // platform keys.
 void GetCertDatabase(base::Optional<TokenId> token_id,
-                     const GetCertDBCallback& callback,
-                     BrowserContext* browser_context,
+                     GetCertDBCallback callback,
+                     PlatformKeysServiceImplDelegate* delegate,
                      NSSOperationState* state) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  Profile* profile = Profile::FromBrowserContext(browser_context);
-  // There will be no public or private slots initialized if no user is logged
-  // in. In this case, an NSS certificate database that has the system slot
-  // should be used for system token operations.
-  if (ProfileHelper::IsSigninProfile(profile)) {
-    SystemTokenCertDBInitializer::Get()->GetSystemTokenCertDb(base::BindOnce(
-        &DidGetSystemTokenCertDbOnUiThread, token_id, callback, state));
-    return;
-  }
-
-  content::GetIOThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(&GetCertDatabaseOnIoThread, token_id, callback,
-                                browser_context->GetResourceContext(), state));
+  delegate->GetNSSCertDatabase(base::BindOnce(&DidGetCertDbOnUiThread, token_id,
+                                              std::move(callback), state));
 }
 
 class GenerateRSAKeyState : public NSSOperationState {
@@ -1422,7 +1378,10 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   auto state = std::make_unique<GenerateRSAKeyState>(
       weak_factory_.GetWeakPtr(), modulus_length_bits, callback);
-
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
   if (modulus_length_bits > kMaxRSAModulusLengthBits) {
     state->OnError(FROM_HERE, kErrorAlgorithmNotSupported);
     return;
@@ -1431,8 +1390,8 @@
   // Get the pointer to |state| before base::Passed releases |state|.
   NSSOperationState* state_ptr = state.get();
   GetCertDatabase(token_id,
-                  base::Bind(&GenerateRSAKeyWithDB, base::Passed(&state)),
-                  browser_context_, state_ptr);
+                  base::BindOnce(&GenerateRSAKeyWithDB, base::Passed(&state)),
+                  delegate_.get(), state_ptr);
 }
 
 void PlatformKeysServiceImpl::GenerateECKey(
@@ -1442,12 +1401,15 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   auto state = std::make_unique<GenerateECKeyState>(weak_factory_.GetWeakPtr(),
                                                     named_curve, callback);
-
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
   // Get the pointer to |state| before base::Passed releases |state|.
   NSSOperationState* state_ptr = state.get();
   GetCertDatabase(token_id,
-                  base::Bind(&GenerateECKeyWithDB, base::Passed(&state)),
-                  browser_context_, state_ptr);
+                  base::BindOnce(&GenerateECKeyWithDB, base::Passed(&state)),
+                  delegate_.get(), state_ptr);
 }
 
 void PlatformKeysServiceImpl::SignRSAPKCS1Digest(
@@ -1461,6 +1423,10 @@
       weak_factory_.GetWeakPtr(), data, public_key_spki_der,
       /*raw_pkcs1=*/false, hash_algorithm,
       /*key_type=*/KeyType::kRsassaPkcs1V15, callback);
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
 
   // Get the pointer to |state| before base::Passed releases |state|.
   NSSOperationState* state_ptr = state.get();
@@ -1468,8 +1434,8 @@
   // The NSSCertDatabase object is not required. But in case it's not available
   // we would get more informative error messages and we can double check that
   // we use a key of the correct token.
-  GetCertDatabase(token_id, base::Bind(&SignWithDB, base::Passed(&state)),
-                  browser_context_, state_ptr);
+  GetCertDatabase(token_id, base::BindOnce(&SignWithDB, base::Passed(&state)),
+                  delegate_.get(), state_ptr);
 }
 
 void PlatformKeysServiceImpl::SignRSAPKCS1Raw(
@@ -1482,6 +1448,10 @@
       weak_factory_.GetWeakPtr(), data, public_key_spki_der,
       /*raw_pkcs1=*/true, HASH_ALGORITHM_NONE,
       /*key_type=*/KeyType::kRsassaPkcs1V15, callback);
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
 
   // Get the pointer to |state| before base::Passed releases |state|.
   NSSOperationState* state_ptr = state.get();
@@ -1489,8 +1459,8 @@
   // The NSSCertDatabase object is not required. But in case it's not available
   // we would get more informative error messages and we can double check that
   // we use a key of the correct token.
-  GetCertDatabase(token_id, base::Bind(&SignWithDB, base::Passed(&state)),
-                  browser_context_, state_ptr);
+  GetCertDatabase(token_id, base::BindOnce(&SignWithDB, base::Passed(&state)),
+                  delegate_.get(), state_ptr);
 }
 
 void PlatformKeysServiceImpl::SignECDSADigest(
@@ -1504,6 +1474,10 @@
       weak_factory_.GetWeakPtr(), data, public_key_spki_der,
       /*raw_pkcs1=*/false, hash_algorithm,
       /*key_type=*/KeyType::kEcdsa, callback);
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
 
   // Get the pointer to |state| before base::Passed releases |state|.
   NSSOperationState* state_ptr = state.get();
@@ -1511,8 +1485,8 @@
   // The NSSCertDatabase object is not required. But in case it's not available
   // we would get more informative error messages and we can double check that
   // we use a key of the correct token.
-  GetCertDatabase(token_id, base::Bind(&SignWithDB, base::Passed(&state)),
-                  browser_context_, state_ptr);
+  GetCertDatabase(token_id, base::BindOnce(&SignWithDB, base::Passed(&state)),
+                  delegate_.get(), state_ptr);
 }
 
 void PlatformKeysServiceImpl::SelectClientCertificates(
@@ -1528,21 +1502,14 @@
   // filtering afterwards.
   cert_request_info->cert_authorities = certificate_authorities;
 
-  const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(
-          Profile::FromBrowserContext(browser_context_));
-
-  // Use the device-wide system key slot only if the user is affiliated on the
-  // device.
-  const bool use_system_key_slot = user->IsAffiliated();
-
   auto state = std::make_unique<SelectCertificatesState>(
       weak_factory_.GetWeakPtr(), cert_request_info, callback);
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
 
-  state->cert_store_ = std::make_unique<ClientCertStoreChromeOS>(
-      nullptr,  // no additional provider
-      use_system_key_slot, user->username_hash(),
-      ClientCertStoreChromeOS::PasswordDelegateFactory());
+  state->cert_store_ = delegate_->CreateClientCertStore();
 
   // Note DidSelectCertificates() may be called synchronously.
   SelectCertificatesState* state_ptr = state.get();
@@ -1683,11 +1650,15 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   auto state = std::make_unique<GetCertificatesState>(
       weak_factory_.GetWeakPtr(), callback);
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
   // Get the pointer to |state| before base::Passed releases |state|.
   NSSOperationState* state_ptr = state.get();
   GetCertDatabase(token_id,
-                  base::Bind(&GetCertificatesWithDB, base::Passed(&state)),
-                  browser_context_, state_ptr);
+                  base::BindOnce(&GetCertificatesWithDB, base::Passed(&state)),
+                  delegate_.get(), state_ptr);
 }
 
 void PlatformKeysServiceImpl::GetAllKeys(TokenId token_id,
@@ -1696,11 +1667,15 @@
 
   auto state = std::make_unique<GetAllKeysState>(weak_factory_.GetWeakPtr(),
                                                  std::move(callback));
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
 
   NSSOperationState* state_ptr = state.get();
   GetCertDatabase(token_id,
-                  base::BindRepeating(&GetAllKeysWithDb, base::Passed(&state)),
-                  browser_context_, state_ptr);
+                  base::BindOnce(&GetAllKeysWithDb, base::Passed(&state)),
+                  delegate_.get(), state_ptr);
 }
 
 void PlatformKeysServiceImpl::ImportCertificate(
@@ -1710,15 +1685,19 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   auto state = std::make_unique<ImportCertificateState>(
       weak_factory_.GetWeakPtr(), certificate, callback);
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
   // Get the pointer to |state| before base::Passed releases |state|.
   NSSOperationState* state_ptr = state.get();
 
   // The NSSCertDatabase object is not required. But in case it's not available
   // we would get more informative error messages and we can double check that
   // we use a key of the correct token.
-  GetCertDatabase(token_id,
-                  base::Bind(&ImportCertificateWithDB, base::Passed(&state)),
-                  browser_context_, state_ptr);
+  GetCertDatabase(
+      token_id, base::BindOnce(&ImportCertificateWithDB, base::Passed(&state)),
+      delegate_.get(), state_ptr);
 }
 
 void PlatformKeysServiceImpl::RemoveCertificate(
@@ -1728,14 +1707,18 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   auto state = std::make_unique<RemoveCertificateState>(
       weak_factory_.GetWeakPtr(), certificate, callback);
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
   // Get the pointer to |state| before base::Passed releases |state|.
   NSSOperationState* state_ptr = state.get();
 
   // The NSSCertDatabase object is not required. But in case it's not available
   // we would get more informative error messages.
-  GetCertDatabase(token_id,
-                  base::Bind(&RemoveCertificateWithDB, base::Passed(&state)),
-                  browser_context_, state_ptr);
+  GetCertDatabase(
+      token_id, base::BindOnce(&RemoveCertificateWithDB, base::Passed(&state)),
+      delegate_.get(), state_ptr);
 }
 
 void PlatformKeysServiceImpl::RemoveKey(TokenId token_id,
@@ -1745,25 +1728,34 @@
 
   auto state = std::make_unique<RemoveKeyState>(
       weak_factory_.GetWeakPtr(), public_key_spki_der, std::move(callback));
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
 
   // Get the pointer to |state| before base::Passed releases |state|.
   NSSOperationState* state_ptr = state.get();
 
   // The NSSCertDatabase object is not required. But in case it's not available
   // we would get more informative error messages.
-  GetCertDatabase(token_id, base::Bind(&RemoveKeyWithDb, base::Passed(&state)),
-                  browser_context_, state_ptr);
+  GetCertDatabase(token_id,
+                  base::BindOnce(&RemoveKeyWithDb, base::Passed(&state)),
+                  delegate_.get(), state_ptr);
 }
 
 void PlatformKeysServiceImpl::GetTokens(const GetTokensCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   auto state =
       std::make_unique<GetTokensState>(weak_factory_.GetWeakPtr(), callback);
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
   // Get the pointer to |state| before base::Passed releases |state|.
   NSSOperationState* state_ptr = state.get();
   GetCertDatabase(/*token_id=*/base::nullopt /* don't get any specific slot */,
                   base::Bind(&GetTokensWithDB, base::Passed(&state)),
-                  browser_context_, state_ptr);
+                  delegate_.get(), state_ptr);
 }
 
 void PlatformKeysServiceImpl::GetKeyLocations(
@@ -1772,12 +1764,16 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   auto state = std::make_unique<GetKeyLocationsState>(
       weak_factory_.GetWeakPtr(), public_key_spki_der, callback);
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
   NSSOperationState* state_ptr = state.get();
 
   GetCertDatabase(
       /*token_id=*/base::nullopt /* don't get any specific slot */,
       base::BindRepeating(&GetKeyLocationsWithDB, base::Passed(&state)),
-      browser_context_, state_ptr);
+      delegate_.get(), state_ptr);
 }
 
 void PlatformKeysServiceImpl::SetAttributeForKey(
@@ -1795,6 +1791,10 @@
   auto state = std::make_unique<SetAttributeForKeyState>(
       weak_factory_.GetWeakPtr(), public_key_spki_der, ck_attribute_type,
       attribute_value, std::move(callback));
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
 
   // Get the pointer to |state| before base::Passed releases |state|.
   NSSOperationState* state_ptr = state.get();
@@ -1802,9 +1802,8 @@
   // The NSSCertDatabase object is not required. Only setting the state slot is
   // required.
   GetCertDatabase(
-      token_id,
-      base::BindRepeating(&SetAttributeForKeyWithDb, base::Passed(&state)),
-      browser_context_, state_ptr);
+      token_id, base::BindOnce(&SetAttributeForKeyWithDb, base::Passed(&state)),
+      delegate_.get(), state_ptr);
 }
 
 void PlatformKeysServiceImpl::GetAttributeForKey(
@@ -1821,6 +1820,10 @@
   auto state = std::make_unique<GetAttributeForKeyState>(
       weak_factory_.GetWeakPtr(), public_key_spki_der, ck_attribute_type,
       std::move(callback));
+  if (delegate_->IsShutDown()) {
+    state->OnError(FROM_HERE, kErrorShutDown);
+    return;
+  }
 
   // Get the pointer to |state| before base::Passed releases |state|.
   NSSOperationState* state_ptr = state.get();
@@ -1828,9 +1831,8 @@
   // The NSSCertDatabase object is not required. Only setting the state slot is
   // required.
   GetCertDatabase(
-      token_id,
-      base::BindRepeating(&GetAttributeForKeyWithDb, base::Passed(&state)),
-      browser_context_, state_ptr);
+      token_id, base::BindOnce(&GetAttributeForKeyWithDb, base::Passed(&state)),
+      delegate_.get(), state_ptr);
 }
 
 void PlatformKeysServiceImpl::SetMapToSoftokenAttrsForTesting(
diff --git a/chrome/browser/chromeos/policy/system_proxy_manager.cc b/chrome/browser/chromeos/policy/system_proxy_manager.cc
index e5500e551..da1efdd 100644
--- a/chrome/browser/chromeos/policy/system_proxy_manager.cc
+++ b/chrome/browser/chromeos/policy/system_proxy_manager.cc
@@ -20,7 +20,12 @@
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
+#include "content/public/browser/storage_partition.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/proxy_server.h"
 #include "net/http/http_auth_scheme.h"
+#include "net/http/http_util.h"
+#include "services/network/public/mojom/network_context.mojom.h"
 
 namespace {
 const char kSystemProxyService[] = "system-proxy-service";
@@ -205,11 +210,33 @@
     const system_proxy::AuthenticationRequiredDetails& details) {
   system_proxy::ProtectionSpace protection_space =
       details.proxy_protection_space();
+  if (!primary_profile_) {
+    LookupProxyAuthCredentialsCallback(protection_space,
+                                       /* credentials = */ base::nullopt);
+    return;
+  }
 
-  // TODO(acostinas, crbug.com/1098216): Get credentials from the network
-  // service.
-  LookupProxyAuthCredentialsCallback(protection_space,
-                                     /* credentials = */ base::nullopt);
+  // TODO(acostinas,chromium:1104818) |protection_space.origin()| is in a
+  // URI-like format which may be incompatible between Chrome and libcurl, which
+  // is used on the Chrome OS side. We should change |origin()| to be a PAC
+  // string (a more "standard" way of representing proxies) and call
+  // |FromPacString()| to create |proxy_server|.
+  net::ProxyServer proxy_server = net::ProxyServer::FromURI(
+      protection_space.origin(), net::ProxyServer::Scheme::SCHEME_HTTP);
+
+  if (!proxy_server.is_valid()) {
+    LookupProxyAuthCredentialsCallback(protection_space,
+                                       /* credentials = */ base::nullopt);
+    return;
+  }
+  content::BrowserContext::GetDefaultStoragePartition(primary_profile_)
+      ->GetNetworkContext()
+      ->LookupProxyAuthCredentials(
+          proxy_server, protection_space.scheme(),
+          net::HttpUtil::Unquote(protection_space.realm()),
+          base::BindOnce(
+              &SystemProxyManager::LookupProxyAuthCredentialsCallback,
+              weak_factory_.GetWeakPtr(), protection_space));
 }
 
 void SystemProxyManager::LookupProxyAuthCredentialsCallback(
diff --git a/chrome/browser/chromeos/policy/system_proxy_manager.h b/chrome/browser/chromeos/policy/system_proxy_manager.h
index 0397f08..078920a6 100644
--- a/chrome/browser/chromeos/policy/system_proxy_manager.h
+++ b/chrome/browser/chromeos/policy/system_proxy_manager.h
@@ -11,6 +11,7 @@
 #include "base/callback_forward.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chromeos/dbus/system_proxy/system_proxy_service.pb.h"
 #include "net/base/auth.h"
@@ -70,8 +71,9 @@
   // This function is called when the |WorkerActive| dbus signal is received.
   void OnWorkerActive(const system_proxy::WorkerActiveSignalDetails& details);
 
-  // This function is called when the |AuthenticationRequired| dbus signal is
-  // received.
+  // Requests from the NetworkService the user credentials associated with the
+  // protection space specified in |details|. This function is called when the
+  // |AuthenticationRequired| dbus signal is received.
   void OnAuthenticationRequired(
       const system_proxy::AuthenticationRequiredDetails& details);
 
diff --git a/chrome/browser/chromeos/policy/system_proxy_manager_unittest.cc b/chrome/browser/chromeos/policy/system_proxy_manager_unittest.cc
index ae89f3d..dc1912b 100644
--- a/chrome/browser/chromeos/policy/system_proxy_manager_unittest.cc
+++ b/chrome/browser/chromeos/policy/system_proxy_manager_unittest.cc
@@ -17,7 +17,19 @@
 #include "chromeos/dbus/system_proxy/system_proxy_client.h"
 #include "chromeos/dbus/system_proxy/system_proxy_service.pb.h"
 #include "components/prefs/pref_service.h"
+#include "content/public/browser/network_service_instance.h"
+#include "content/public/browser/storage_partition.h"
 #include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_utils.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "net/http/http_auth.h"
+#include "net/http/http_auth_cache.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_transaction_factory.h"
+#include "net/url_request/url_request_context.h"
+#include "services/network/network_context.h"
+#include "services/network/network_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -28,13 +40,40 @@
 namespace {
 constexpr char kSystemServicesUsername[] = "test_username";
 constexpr char kSystemServicesPassword[] = "test_password";
+constexpr char kBrowserUsername[] = "browser_username";
+constexpr char kBrowserPassword[] = "browser_password";
 constexpr char kKerberosActivePrincipalName[] = "kerberos_princ_name";
 constexpr char kProxyAuthUrl[] = "http://example.com:3128";
+constexpr char kProxyAuthEmptyPath[] = "http://example.com:3128/";
 constexpr char kRealm[] = "My proxy";
-constexpr char kScheme[] = "BaSiC";
+constexpr char kScheme[] = "dIgEsT";
+constexpr char kProxyAuthChallenge[] = "challenge";
+
+std::unique_ptr<network::NetworkContext>
+CreateNetworkContextForDefaultStoragePartition(
+    network::NetworkService* network_service,
+    content::BrowserContext* browser_context) {
+  mojo::PendingRemote<network::mojom::NetworkContext> network_context_remote;
+  auto network_context = std::make_unique<network::NetworkContext>(
+      network_service, network_context_remote.InitWithNewPipeAndPassReceiver(),
+      network::mojom::NetworkContextParams::New());
+  content::BrowserContext::GetDefaultStoragePartition(browser_context)
+      ->SetNetworkContextForTesting(std::move(network_context_remote));
+  return network_context;
+}
+
+network::NetworkService* GetNetworkService() {
+  content::GetNetworkService();
+  // Wait for the Network Service to initialize on the IO thread.
+  content::RunAllPendingInMessageLoop(content::BrowserThread::IO);
+  return network::NetworkService::GetNetworkServiceForTesting();
+}
+
 }  // namespace
 
 namespace policy {
+// TODO(acostinas, https://crbug.com/1102351) Replace RunUntilIdle() in tests
+// with RunLoop::Run() with explicit RunLoop::QuitClosure().
 class SystemProxyManagerTest : public testing::Test {
  public:
   SystemProxyManagerTest() : local_state_(TestingBrowserProcess::GetGlobal()) {}
@@ -158,7 +197,7 @@
 }
 
 // Tests that when no user is signed in, credential requests are resolved to a
-// d-bus call which sends back to System-proxy empty credentials for the
+// D-Bus call which sends back to System-proxy empty credentials for the
 // specified protection space.
 TEST_F(SystemProxyManagerTest, UserCredentialsRequiredNoUser) {
   SystemProxyManager system_proxy_manager(chromeos::CrosSettings::Get(),
@@ -190,4 +229,56 @@
   EXPECT_EQ("", request.credentials().username());
   EXPECT_EQ("", request.credentials().password());
 }
+
+// Tests that credential requests are resolved to a  D-Bus call which sends back
+// to System-proxy credentials acquired from the NetworkService.
+TEST_F(SystemProxyManagerTest, UserCredentialsRequestedFromNetworkService) {
+  SystemProxyManager system_proxy_manager(chromeos::CrosSettings::Get(),
+                                          local_state_.Get());
+  SetPolicy(true /* system_proxy_enabled */, "" /* system_services_username */,
+            "" /* system_services_password */);
+  system_proxy_manager.StartObservingPrimaryProfilePrefs(profile_.get());
+
+  // Setup the NetworkContext with credentials.
+  std::unique_ptr<network::NetworkContext> network_context =
+      CreateNetworkContextForDefaultStoragePartition(GetNetworkService(),
+                                                     profile_.get());
+  network_context->url_request_context()
+      ->http_transaction_factory()
+      ->GetSession()
+      ->http_auth_cache()
+      ->Add(GURL(kProxyAuthEmptyPath), net::HttpAuth::AUTH_PROXY, kRealm,
+            net::HttpAuth::AUTH_SCHEME_DIGEST, net::NetworkIsolationKey(),
+            kProxyAuthChallenge,
+            net::AuthCredentials(base::ASCIIToUTF16(kBrowserUsername),
+                                 base::ASCIIToUTF16(kBrowserPassword)),
+            std::string() /* path */);
+
+  system_proxy::ProtectionSpace protection_space;
+  protection_space.set_origin(kProxyAuthUrl);
+  protection_space.set_scheme(kScheme);
+  protection_space.set_realm(kRealm);
+
+  system_proxy::AuthenticationRequiredDetails details;
+  *details.mutable_proxy_protection_space() = protection_space;
+
+  EXPECT_EQ(1, client_test_interface()->GetSetAuthenticationDetailsCallCount());
+
+  client_test_interface()->SendAuthenticationRequiredSignal(details);
+  task_environment_.RunUntilIdle();
+
+  EXPECT_EQ(2, client_test_interface()->GetSetAuthenticationDetailsCallCount());
+
+  system_proxy::SetAuthenticationDetailsRequest request =
+      client_test_interface()->GetLastAuthenticationDetailsRequest();
+
+  ASSERT_TRUE(request.has_protection_space());
+  EXPECT_EQ(protection_space.SerializeAsString(),
+            request.protection_space().SerializeAsString());
+
+  ASSERT_TRUE(request.has_credentials());
+  EXPECT_EQ(kBrowserUsername, request.credentials().username());
+  EXPECT_EQ(kBrowserPassword, request.credentials().password());
+  system_proxy_manager.StopObservingPrimaryProfilePrefs();
+}
 }  // namespace policy
diff --git a/chrome/browser/chromeos/system_token_cert_db_initializer.cc b/chrome/browser/chromeos/system_token_cert_db_initializer.cc
index d5010017..3376299 100644
--- a/chrome/browser/chromeos/system_token_cert_db_initializer.cc
+++ b/chrome/browser/chromeos/system_token_cert_db_initializer.cc
@@ -108,6 +108,17 @@
   // Note that the observer could potentially not be added yet, but
   // RemoveObserver() is a no-op in that case.
   CryptohomeClient::Get()->RemoveObserver(this);
+
+  // Cancel any in-progress initialization sequence.
+  weak_ptr_factory_.InvalidateWeakPtrs();
+
+  // Notify observers that the SystemTokenCertDBInitializer and the
+  // NSSCertDatabase it provides can not be used anymore.
+  for (auto& observer : observers_)
+    observer.OnSystemTokenCertDBDestroyed();
+
+  // Now it's safe to destroy the NSSCertDatabase.
+  system_token_cert_database_.reset();
 }
 
 void SystemTokenCertDBInitializer::TpmInitStatusUpdated(
@@ -134,6 +145,18 @@
     get_system_token_cert_db_callback_list_.push_back(std::move(callback));
 }
 
+void SystemTokenCertDBInitializer::AddObserver(
+    SystemTokenCertDBObserver* observer) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  observers_.AddObserver(observer);
+}
+
+void SystemTokenCertDBInitializer::RemoveObserver(
+    SystemTokenCertDBObserver* observer) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  observers_.RemoveObserver(observer);
+}
+
 void SystemTokenCertDBInitializer::OnCryptohomeAvailable(bool available) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
diff --git a/chrome/browser/chromeos/system_token_cert_db_initializer.h b/chrome/browser/chromeos/system_token_cert_db_initializer.h
index cfd08ad..1950607 100644
--- a/chrome/browser/chromeos/system_token_cert_db_initializer.h
+++ b/chrome/browser/chromeos/system_token_cert_db_initializer.h
@@ -11,6 +11,8 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "base/optional.h"
 #include "base/sequence_checker.h"
 #include "chromeos/dbus/cryptohome/cryptohome_client.h"
@@ -22,6 +24,16 @@
 
 namespace chromeos {
 
+// An observer that gets notified when the global NSSCertDatabase is about to be
+// destroyed.
+class SystemTokenCertDBObserver : public base::CheckedObserver {
+ public:
+  // Called when the global NSSCertDatabase is about to be destroyed.
+  // Consumers of that database should drop any reference to it and stop using
+  // it.
+  virtual void OnSystemTokenCertDBDestroyed() = 0;
+};
+
 // Initializes a global NSSCertDatabase for the system token and starts
 // NetworkCertLoader with that database.
 //
@@ -50,10 +62,17 @@
   // |callback|. If the database is already initialized, calls |callback|
   // immediately. Otherwise, |callback| will be called when the database is
   // initialized.
+  // To be notified when the returned NSSCertDatabase becomes invalid, callers
+  // should register as SystemTokenCertDBObserver.
   using GetSystemTokenCertDbCallback =
       base::OnceCallback<void(net::NSSCertDatabase*)>;
   void GetSystemTokenCertDb(GetSystemTokenCertDbCallback callback);
 
+  // Adds |observer| as SystemTokenCertDBObserver.
+  void AddObserver(SystemTokenCertDBObserver* observer);
+  // Removes |observer| as SystemTokenCertDBObserver.
+  void RemoveObserver(SystemTokenCertDBObserver* observer);
+
  private:
   // Called once the cryptohome service is available.
   void OnCryptohomeAvailable(bool available);
@@ -86,6 +105,10 @@
   std::vector<GetSystemTokenCertDbCallback>
       get_system_token_cert_db_callback_list_;
 
+  // List of observers that will be notified when the global system token
+  // NSSCertDatabase is destroyed.
+  base::ObserverList<SystemTokenCertDBObserver> observers_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   base::WeakPtrFactory<SystemTokenCertDBInitializer> weak_ptr_factory_{this};
diff --git a/chrome/browser/client_hints/OWNERS b/chrome/browser/client_hints/OWNERS
index 22542699..6908cd0a 100644
--- a/chrome/browser/client_hints/OWNERS
+++ b/chrome/browser/client_hints/OWNERS
@@ -1,6 +1,7 @@
 yoavweiss@chromium.org
 tbansal@chromium.org
 ryansturm@chromium.org
+aarontag@chromium.org
 
 # For IPC security review
 per-file *.mojom=set noparent
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc
index c66d330..b80275d 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc
@@ -316,6 +316,12 @@
           *args_);
   EXTENSION_FUNCTION_VALIDATE(parameters);
 
+  if (parameters->new_password.empty()) {
+    return RespondNow(
+        Error("Could not change the compromised credential. The new password "
+              "can't be empty."));
+  }
+
   if (!GetDelegate(browser_context())
            ->ChangeCompromisedCredential(parameters->credential,
                                          parameters->new_password)) {
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_apitest.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_apitest.cc
index 45337a9..ec2f6b27 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_apitest.cc
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_apitest.cc
@@ -214,6 +214,13 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
+                       ChangeCompromisedCredentialWithEmptyPasswordFails) {
+  EXPECT_TRUE(
+      RunPasswordsSubtest("changeCompromisedCredentialWithEmptyPasswordFails"))
+      << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
                        ChangeCompromisedCredentialFails) {
   EXPECT_TRUE(RunPasswordsSubtest("changeCompromisedCredentialFails"))
       << message_;
diff --git a/chrome/browser/extensions/api/streams_private/streams_private_api.cc b/chrome/browser/extensions/api/streams_private/streams_private_api.cc
index bb4af72..70a275c8 100644
--- a/chrome/browser/extensions/api/streams_private/streams_private_api.cc
+++ b/chrome/browser/extensions/api/streams_private/streams_private_api.cc
@@ -26,7 +26,7 @@
     int frame_tree_node_id,
     int render_process_id,
     int render_frame_id,
-    content::mojom::TransferrableURLLoaderPtr transferrable_loader,
+    blink::mojom::TransferrableURLLoaderPtr transferrable_loader,
     const GURL& original_url) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
diff --git a/chrome/browser/extensions/api/streams_private/streams_private_api.h b/chrome/browser/extensions/api/streams_private/streams_private_api.h
index 01197a0..1fd16ff4 100644
--- a/chrome/browser/extensions/api/streams_private/streams_private_api.h
+++ b/chrome/browser/extensions/api/streams_private/streams_private_api.h
@@ -9,7 +9,7 @@
 #include <string>
 
 #include "base/macros.h"
-#include "content/public/common/transferrable_url_loader.mojom.h"
+#include "third_party/blink/public/mojom/loader/transferrable_url_loader.mojom.h"
 
 namespace extensions {
 
@@ -35,7 +35,7 @@
       int frame_tree_node_id,
       int render_process_id,
       int render_frame_id,
-      content::mojom::TransferrableURLLoaderPtr transferrable_loader,
+      blink::mojom::TransferrableURLLoaderPtr transferrable_loader,
       const GURL& original_url);
 };
 
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index cf12dab0..1f885c9d 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -51,6 +51,7 @@
 #include "extensions/browser/install/crx_install_error.h"
 #include "extensions/browser/install/extension_install_ui.h"
 #include "extensions/browser/install_flag.h"
+#include "extensions/browser/install_stage.h"
 #include "extensions/browser/notification_types.h"
 #include "extensions/browser/policy_check.h"
 #include "extensions/browser/preload_check_group.h"
@@ -523,6 +524,7 @@
   extension_ = extension;
   temp_dir_ = temp_dir;
   ruleset_checksums_ = std::move(ruleset_checksums);
+  ReportInstallationStage(InstallationStage::kFinalizing);
 
   if (!install_icon.empty())
     install_icon_ = std::make_unique<SkBitmap>(install_icon);
@@ -574,6 +576,10 @@
     NOTREACHED();
 }
 
+void CrxInstaller::OnStageChanged(InstallationStage stage) {
+  ReportInstallationStage(stage);
+}
+
 void CrxInstaller::CheckInstall() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   ExtensionService* service = service_weak_.get();
@@ -716,6 +722,7 @@
 
 void CrxInstaller::ConfirmInstall() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  ReportInstallationStage(InstallationStage::kComplete);
   ExtensionService* service = service_weak_.get();
   if (!service || service->browser_terminating())
     return;
@@ -1011,6 +1018,28 @@
   NotifyCrxInstallComplete(base::nullopt);
 }
 
+void CrxInstaller::ReportInstallationStage(InstallationStage stage) {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+    DCHECK(installer_task_runner_->RunsTasksInCurrentSequence());
+    if (!content::GetUIThreadTaskRunner({})->PostTask(
+            FROM_HERE, base::BindOnce(&CrxInstaller::ReportInstallationStage,
+                                      this, stage))) {
+      NOTREACHED();
+    }
+    return;
+  }
+
+  if (!service_weak_.get() || service_weak_->browser_terminating())
+    return;
+  // In case of force installed extensions, expected_id_ should always be set.
+  // We do not want to report in case of other extensions.
+  if (expected_id_.empty())
+    return;
+  InstallStageTracker* install_stage_tracker =
+      InstallStageTracker::Get(profile_);
+  install_stage_tracker->ReportCRXInstallationStage(expected_id_, stage);
+}
+
 void CrxInstaller::NotifyCrxInstallBegin() {
   InstallTrackerFactory::GetForBrowserContext(profile())
       ->OnBeginCrxInstall(expected_id_);
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index b5ad3618..c1b7795 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -42,6 +42,7 @@
 class CrxInstallError;
 class ExtensionService;
 class ExtensionUpdaterTest;
+enum class InstallationStage;
 class PreloadCheckGroup;
 
 // This class installs a crx file into a profile.
@@ -297,6 +298,7 @@
       const Extension* extension,
       const SkBitmap& install_icon,
       declarative_net_request::RulesetChecksums ruleset_checksums) override;
+  void OnStageChanged(InstallationStage stage) override;
 
   // Called on the UI thread to start the requirements, policy and blocklist
   // checks on the extension.
@@ -326,6 +328,8 @@
   void ReportFailureFromUIThread(const CrxInstallError& error);
   void ReportSuccessFromFileThread();
   void ReportSuccessFromUIThread();
+  // Always report from the UI thread.
+  void ReportInstallationStage(InstallationStage stage);
   void NotifyCrxInstallBegin();
   void NotifyCrxInstallComplete(const base::Optional<CrxInstallError>& error);
 
diff --git a/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc b/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc
index d783a7b..52dc4fef 100644
--- a/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc
+++ b/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc
@@ -152,6 +152,16 @@
   }
 }
 
+void InstallStageTracker::ReportCRXInstallationStage(const ExtensionId& id,
+                                                     InstallationStage stage) {
+  DCHECK(!id.empty());
+  InstallationData& data = installation_data_map_[id];
+  data.installation_stage = stage;
+  for (auto& observer : observers_) {
+    observer.OnExtensionDataChangedForTesting(id, browser_context_, data);
+  }
+}
+
 void InstallStageTracker::ReportDownloadingCacheStatus(
     const ExtensionId& id,
     ExtensionDownloaderDelegate::CacheStatus cache_status) {
diff --git a/chrome/browser/extensions/forced_extensions/install_stage_tracker.h b/chrome/browser/extensions/forced_extensions/install_stage_tracker.h
index 08922be..2b4fc09 100644
--- a/chrome/browser/extensions/forced_extensions/install_stage_tracker.h
+++ b/chrome/browser/extensions/forced_extensions/install_stage_tracker.h
@@ -14,6 +14,7 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "extensions/browser/install/crx_install_error.h"
 #include "extensions/browser/install/sandboxed_unpacker_failure_reason.h"
+#include "extensions/browser/install_stage.h"
 #include "extensions/browser/updater/extension_downloader_delegate.h"
 #include "extensions/browser/updater/safe_manifest_parser.h"
 #include "extensions/common/extension_id.h"
@@ -295,6 +296,8 @@
     // Time at which the update manifest is downloaded and successfully parsed
     // from the server.
     base::Optional<base::Time> download_manifest_finish_time;
+    // See InstallationStage enum.
+    base::Optional<InstallationStage> installation_stage;
   };
 
   class Observer : public base::CheckedObserver {
@@ -347,6 +350,8 @@
   void ReportFailure(const ExtensionId& id, FailureReason reason);
   void ReportDownloadingStage(const ExtensionId& id,
                               ExtensionDownloaderDelegate::Stage stage);
+  void ReportCRXInstallationStage(const ExtensionId& id,
+                                  InstallationStage stage);
   void ReportDownloadingCacheStatus(
       const ExtensionId& id,
       ExtensionDownloaderDelegate::CacheStatus cache_status);
diff --git a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc
index 2a444e8..7570d1d 100644
--- a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc
+++ b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc
@@ -151,7 +151,7 @@
       const GURL& url,
       std::string* view_id) {
     *view_id = base::GenerateGUID();
-    auto transferrable_loader = content::mojom::TransferrableURLLoader::New();
+    auto transferrable_loader = blink::mojom::TransferrableURLLoader::New();
     transferrable_loader->url = url;
     transferrable_loader->head = network::mojom::URLResponseHead::New();
     transferrable_loader->head->mime_type = "application/pdf";
diff --git a/chrome/browser/history/history_service_factory.cc b/chrome/browser/history/history_service_factory.cc
index 3ef673e..8ae55f1 100644
--- a/chrome/browser/history/history_service_factory.cc
+++ b/chrome/browser/history/history_service_factory.cc
@@ -19,6 +19,23 @@
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/prefs/pref_service.h"
 
+namespace {
+
+std::unique_ptr<KeyedService> BuildHistoryService(
+    content::BrowserContext* context) {
+  auto history_service = std::make_unique<history::HistoryService>(
+      std::make_unique<ChromeHistoryClient>(
+          BookmarkModelFactory::GetForBrowserContext(context)),
+      std::make_unique<history::ContentVisitDelegate>(context));
+  if (!history_service->Init(
+          history::HistoryDatabaseParamsForPath(context->GetPath()))) {
+    return nullptr;
+  }
+  return history_service;
+}
+
+}  // namespace
+
 // static
 history::HistoryService* HistoryServiceFactory::GetForProfile(
     Profile* profile,
@@ -65,6 +82,12 @@
   factory->BrowserContextDestroyed(profile);
 }
 
+// static
+BrowserContextKeyedServiceFactory::TestingFactory
+HistoryServiceFactory::GetDefaultFactory() {
+  return base::BindRepeating(&BuildHistoryService);
+}
+
 HistoryServiceFactory::HistoryServiceFactory()
     : BrowserContextKeyedServiceFactory(
           "HistoryService",
@@ -77,16 +100,7 @@
 
 KeyedService* HistoryServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
-  std::unique_ptr<history::HistoryService> history_service(
-      new history::HistoryService(
-          std::make_unique<ChromeHistoryClient>(
-              BookmarkModelFactory::GetForBrowserContext(context)),
-          std::make_unique<history::ContentVisitDelegate>(context)));
-  if (!history_service->Init(
-          history::HistoryDatabaseParamsForPath(context->GetPath()))) {
-    return nullptr;
-  }
-  return history_service.release();
+  return BuildHistoryService(context).release();
 }
 
 content::BrowserContext* HistoryServiceFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/history/history_service_factory.h b/chrome/browser/history/history_service_factory.h
index e11fb29..1af52d61 100644
--- a/chrome/browser/history/history_service_factory.h
+++ b/chrome/browser/history/history_service_factory.h
@@ -36,6 +36,9 @@
   // calling test is expected to do the cleanup before calling this function.
   static void ShutdownForProfile(Profile* profile);
 
+  // Returns the default factory, useful in tests where it's null by default.
+  static TestingFactory GetDefaultFactory();
+
  private:
   friend struct base::DefaultSingletonTraits<HistoryServiceFactory>;
 
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service.h b/chrome/browser/nearby_sharing/nearby_sharing_service.h
index 894f925..cb5a094 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service.h
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service.h
@@ -41,16 +41,14 @@
 
   // Registers a send surface for handling payload transfer status and device
   // discovery.
-  virtual void RegisterSendSurface(
+  virtual StatusCodes RegisterSendSurface(
       TransferUpdateCallback* transfer_callback,
-      ShareTargetDiscoveredCallback* discovery_callback,
-      StatusCodesCallback status_codes_callback) = 0;
+      ShareTargetDiscoveredCallback* discovery_callback) = 0;
 
   // Unregisters the current send surface.
-  virtual void UnregisterSendSurface(
+  virtual StatusCodes UnregisterSendSurface(
       TransferUpdateCallback* transfer_callback,
-      ShareTargetDiscoveredCallback* discovery_callback,
-      StatusCodesCallback status_codes_callback) = 0;
+      ShareTargetDiscoveredCallback* discovery_callback) = 0;
 
   // Registers a receiver surface for handling payload transfer status.
   virtual StatusCodes RegisterReceiveSurface(
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
index 220c408..dae2abc8 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/task_runner_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/nearby_sharing/fast_initiation_manager.h"
 #include "chrome/browser/nearby_sharing/logging/logging.h"
@@ -150,26 +151,28 @@
     bluetooth_adapter_->RemoveObserver(this);
 }
 
-void NearbySharingServiceImpl::RegisterSendSurface(
+NearbySharingService::StatusCodes NearbySharingServiceImpl::RegisterSendSurface(
     TransferUpdateCallback* transfer_callback,
-    ShareTargetDiscoveredCallback* discovery_callback,
-    StatusCodesCallback status_codes_callback) {
-  register_send_surface_callback_ = std::move(status_codes_callback);
+    ShareTargetDiscoveredCallback* discovery_callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   StartFastInitiationAdvertising();
+  return StatusCodes::kOk;
 }
 
-void NearbySharingServiceImpl::UnregisterSendSurface(
+NearbySharingService::StatusCodes
+NearbySharingServiceImpl::UnregisterSendSurface(
     TransferUpdateCallback* transfer_callback,
-    ShareTargetDiscoveredCallback* discovery_callback,
-    StatusCodesCallback status_codes_callback) {
-  unregister_send_surface_callback_ = std::move(status_codes_callback);
+    ShareTargetDiscoveredCallback* discovery_callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   StopFastInitiationAdvertising();
+  return StatusCodes::kOk;
 }
 
 NearbySharingService::StatusCodes
 NearbySharingServiceImpl::RegisterReceiveSurface(
     TransferUpdateCallback* transfer_callback,
     ReceiveSurfaceState state) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(transfer_callback);
   DCHECK_NE(state, ReceiveSurfaceState::kUnknown);
   if (foreground_receive_callbacks_.HasObserver(transfer_callback) ||
@@ -202,6 +205,7 @@
 NearbySharingService::StatusCodes
 NearbySharingServiceImpl::UnregisterReceiveSurface(
     TransferUpdateCallback* transfer_callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(transfer_callback);
   bool is_foreground =
       foreground_receive_callbacks_.HasObserver(transfer_callback);
@@ -307,6 +311,7 @@
     const std::string& endpoint_id,
     const std::vector<uint8_t>& endpoint_info,
     std::unique_ptr<NearbyConnection> connection) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // TODO(crbug/1085068): Handle incoming connection; use CertificateManager
 }
 
@@ -384,15 +389,13 @@
 
 void NearbySharingServiceImpl::StartFastInitiationAdvertising() {
   if (!IsBluetoothPresent() || !IsBluetoothPowered()) {
-    std::move(register_send_surface_callback_).Run(StatusCodes::kError);
+    NS_LOG(INFO) << "Failed to advertise FastInitiation. Bluetooth is not "
+                    "present or powered.";
     return;
   }
 
   if (fast_initiation_manager_) {
-    // TODO(hansenmichael): Do not invoke
-    // |register_send_surface_callback_| until Nearby Connections
-    // scanning is kicked off.
-    std::move(register_send_surface_callback_).Run(StatusCodes::kOk);
+    NS_LOG(INFO) << "Failed to advertise FastInitiation. Already advertising.";
     return;
   }
 
@@ -413,8 +416,7 @@
 
 void NearbySharingServiceImpl::StopFastInitiationAdvertising() {
   if (!fast_initiation_manager_) {
-    if (unregister_send_surface_callback_)
-      std::move(unregister_send_surface_callback_).Run(StatusCodes::kOk);
+    NS_LOG(INFO) << "Can't stop advertising FastInitiation. Not advertising.";
     return;
   }
 
@@ -431,7 +433,7 @@
   // Because this will be called from the constructor, GetAdapter() may call
   // OnGetBluetoothAdapter() immediately which can cause problems during tests
   // since the class is not fully constructed yet.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(
           &device::BluetoothAdapterFactory::GetAdapter,
@@ -450,22 +452,17 @@
   // TODO(hansenmichael): Do not invoke
   // |register_send_surface_callback_| until Nearby Connections
   // scanning is kicked off.
-  std::move(register_send_surface_callback_).Run(StatusCodes::kOk);
+  NS_LOG(VERBOSE) << "Started advertising FastInitiation.";
 }
 
 void NearbySharingServiceImpl::OnStartFastInitiationAdvertisingError() {
   fast_initiation_manager_.reset();
-  std::move(register_send_surface_callback_).Run(StatusCodes::kError);
+  NS_LOG(ERROR) << "Failed to start FastInitiation advertising.";
 }
 
 void NearbySharingServiceImpl::OnStopFastInitiationAdvertising() {
   fast_initiation_manager_.reset();
-
-  // TODO(hansenmichael): Do not invoke
-  // |unregister_send_surface_callback_| until Nearby Connections
-  // scanning is stopped.
-  if (unregister_send_surface_callback_)
-    std::move(unregister_send_surface_callback_).Run(StatusCodes::kOk);
+  NS_LOG(VERBOSE) << "Stopped advertising FastInitiation";
 }
 
 bool NearbySharingServiceImpl::IsBluetoothPresent() const {
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
index a6d9eaf0..1b18f47 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
@@ -13,6 +13,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
+#include "base/sequence_checker.h"
 #include "chrome/browser/nearby_sharing/nearby_connections_manager.h"
 #include "chrome/browser/nearby_sharing/nearby_constants.h"
 #include "chrome/browser/nearby_sharing/nearby_notification_manager.h"
@@ -26,6 +27,7 @@
 class PrefService;
 class Profile;
 
+// All methods should be called from the same sequence that created the service.
 class NearbySharingServiceImpl
     : public NearbySharingService,
       public KeyedService,
@@ -40,13 +42,12 @@
   ~NearbySharingServiceImpl() override;
 
   // NearbySharingService:
-  void RegisterSendSurface(TransferUpdateCallback* transfer_callback,
-                           ShareTargetDiscoveredCallback* discovery_callback,
-                           StatusCodesCallback status_codes_callback) override;
-  void UnregisterSendSurface(
+  StatusCodes RegisterSendSurface(
       TransferUpdateCallback* transfer_callback,
-      ShareTargetDiscoveredCallback* discovery_callback,
-      StatusCodesCallback status_codes_callback) override;
+      ShareTargetDiscoveredCallback* discovery_callback) override;
+  StatusCodes UnregisterSendSurface(
+      TransferUpdateCallback* transfer_callback,
+      ShareTargetDiscoveredCallback* discovery_callback) override;
   StatusCodes RegisterReceiveSurface(TransferUpdateCallback* transfer_callback,
                                      ReceiveSurfaceState state) override;
   StatusCodes UnregisterReceiveSurface(
@@ -110,8 +111,6 @@
       nearby_process_observer_{this};
   scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
   std::unique_ptr<FastInitiationManager> fast_initiation_manager_;
-  StatusCodesCallback register_send_surface_callback_;
-  StatusCodesCallback unregister_send_surface_callback_;
   NearbyNotificationManager nearby_notification_manager_;
 
   // A list of foreground receivers.
@@ -143,6 +142,7 @@
   // True if we're currently sending or receiving a file.
   bool is_transferring_files_ = false;
 
+  SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<NearbySharingServiceImpl> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc
index cf106d0..fe105f2d 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
+#include "base/test/bind_test_util.h"
 #include "chrome/browser/nearby_sharing/fake_nearby_connections_manager.h"
 #include "chrome/browser/nearby_sharing/fast_initiation_manager.h"
 #include "chrome/browser/nearby_sharing/nearby_connections_manager.h"
@@ -181,40 +182,6 @@
         fast_initiation_manager_factory_.get());
   }
 
-  NearbySharingService::StatusCodes RegisterSendSurfaceAndWait() {
-    base::RunLoop run_loop;
-    NearbySharingService::StatusCodes result;
-    service_->RegisterSendSurface(
-        /*transfer_callback=*/nullptr, /*discovery_callback=*/nullptr,
-        base::BindOnce(
-            [](base::OnceClosure quit_closure,
-               NearbySharingService::StatusCodes* result,
-               NearbySharingService::StatusCodes code) {
-              *result = code;
-              std::move(quit_closure).Run();
-            },
-            run_loop.QuitClosure(), &result));
-    run_loop.Run();
-    return result;
-  }
-
-  NearbySharingService::StatusCodes UnregisterSendSurfaceAndWait() {
-    base::RunLoop run_loop;
-    NearbySharingService::StatusCodes result;
-    service_->UnregisterSendSurface(
-        /*transfer_callback=*/nullptr, /*discovery_callback=*/nullptr,
-        base::BindOnce(
-            [](base::OnceClosure quit_closure,
-               NearbySharingService::StatusCodes* result,
-               NearbySharingService::StatusCodes code) {
-              *result = code;
-              std::move(quit_closure).Run();
-            },
-            run_loop.QuitClosure(), &result));
-    run_loop.Run();
-    return result;
-  }
-
   bool IsBluetoothPresent() { return is_bluetooth_present_; }
   bool IsBluetoothPowered() { return is_bluetooth_powered_; }
 
@@ -265,42 +232,49 @@
 
 TEST_F(NearbySharingServiceImplTest, StartFastInitiationAdvertising) {
   EXPECT_EQ(NearbySharingService::StatusCodes::kOk,
-            RegisterSendSurfaceAndWait());
+            service_->RegisterSendSurface(/*transfer_callback=*/nullptr,
+                                          /*discovery_callback=*/nullptr));
   EXPECT_EQ(1u, fast_initiation_manager_factory_->StartAdvertisingCount());
 
   // Call RegisterSendSurface() a second time and make sure StartAdvertising is
   // not called again.
   EXPECT_EQ(NearbySharingService::StatusCodes::kOk,
-            RegisterSendSurfaceAndWait());
+            service_->RegisterSendSurface(/*transfer_callback=*/nullptr,
+                                          /*discovery_callback=*/nullptr));
   EXPECT_EQ(1u, fast_initiation_manager_factory_->StartAdvertisingCount());
 }
 
 TEST_F(NearbySharingServiceImplTest, StartFastInitiationAdvertisingError) {
   SetFakeFastInitiationManagerFactory(/*should_succeed_on_start=*/false);
-  EXPECT_EQ(NearbySharingService::StatusCodes::kError,
-            RegisterSendSurfaceAndWait());
+  EXPECT_EQ(NearbySharingService::StatusCodes::kOk,
+            service_->RegisterSendSurface(/*transfer_callback=*/nullptr,
+                                          /*discovery_callback=*/nullptr));
 }
 
 TEST_F(NearbySharingServiceImplTest,
        StartFastInitiationAdvertising_BluetoothNotPresent) {
   is_bluetooth_present_ = false;
-  EXPECT_EQ(NearbySharingService::StatusCodes::kError,
-            RegisterSendSurfaceAndWait());
+  EXPECT_EQ(NearbySharingService::StatusCodes::kOk,
+            service_->RegisterSendSurface(/*transfer_callback=*/nullptr,
+                                          /*discovery_callback=*/nullptr));
 }
 
 TEST_F(NearbySharingServiceImplTest,
        StartFastInitiationAdvertising_BluetoothNotPowered) {
   is_bluetooth_powered_ = false;
-  EXPECT_EQ(NearbySharingService::StatusCodes::kError,
-            RegisterSendSurfaceAndWait());
+  EXPECT_EQ(NearbySharingService::StatusCodes::kOk,
+            service_->RegisterSendSurface(/*transfer_callback=*/nullptr,
+                                          /*discovery_callback=*/nullptr));
 }
 
 TEST_F(NearbySharingServiceImplTest, StopFastInitiationAdvertising) {
   EXPECT_EQ(NearbySharingService::StatusCodes::kOk,
-            RegisterSendSurfaceAndWait());
+            service_->RegisterSendSurface(/*transfer_callback=*/nullptr,
+                                          /*discovery_callback=*/nullptr));
   EXPECT_EQ(1u, fast_initiation_manager_factory_->StartAdvertisingCount());
   EXPECT_EQ(NearbySharingService::StatusCodes::kOk,
-            UnregisterSendSurfaceAndWait());
+            service_->UnregisterSendSurface(/*transfer_callback=*/nullptr,
+                                            /*discovery_callback=*/nullptr));
   EXPECT_TRUE(fast_initiation_manager_factory_
                   ->StopAdvertisingCalledAndManagerDestroyed());
 }
@@ -308,7 +282,8 @@
 TEST_F(NearbySharingServiceImplTest,
        StopFastInitiationAdvertising_BluetoothBecomesNotPresent) {
   EXPECT_EQ(NearbySharingService::StatusCodes::kOk,
-            RegisterSendSurfaceAndWait());
+            service_->RegisterSendSurface(/*transfer_callback=*/nullptr,
+                                          /*discovery_callback=*/nullptr));
   adapter_observer_->AdapterPresentChanged(mock_bluetooth_adapter_.get(),
                                            false);
   EXPECT_TRUE(fast_initiation_manager_factory_
@@ -318,7 +293,8 @@
 TEST_F(NearbySharingServiceImplTest,
        StopFastInitiationAdvertising_BluetoothBecomesNotPowered) {
   EXPECT_EQ(NearbySharingService::StatusCodes::kOk,
-            RegisterSendSurfaceAndWait());
+            service_->RegisterSendSurface(/*transfer_callback=*/nullptr,
+                                          /*discovery_callback=*/nullptr));
   adapter_observer_->AdapterPoweredChanged(mock_bluetooth_adapter_.get(),
                                            false);
   EXPECT_TRUE(fast_initiation_manager_factory_
diff --git a/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc b/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc
index a692d5e3..f8693f1 100644
--- a/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc
+++ b/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc
@@ -15,7 +15,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/download_utils.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/common/transferrable_url_loader.mojom.h"
 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_attach_helper.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
@@ -26,6 +25,7 @@
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
 #include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
+#include "third_party/blink/public/mojom/loader/transferrable_url_loader.mojom.h"
 
 PluginResponseInterceptorURLLoaderThrottle::
     PluginResponseInterceptorURLLoaderThrottle(int resource_type,
@@ -114,7 +114,7 @@
             response_head->headers->raw_headers());
   }
 
-  auto transferrable_loader = content::mojom::TransferrableURLLoader::New();
+  auto transferrable_loader = blink::mojom::TransferrableURLLoader::New();
   transferrable_loader->url = GURL(
       extensions::Extension::GetBaseURLFromExtensionId(extension_id).spec() +
       base::GenerateGUID());
diff --git a/chrome/browser/predictors/preconnect_manager.cc b/chrome/browser/predictors/preconnect_manager.cc
index d7e470b..3f363b5 100644
--- a/chrome/browser/predictors/preconnect_manager.cc
+++ b/chrome/browser/predictors/preconnect_manager.cc
@@ -231,7 +231,8 @@
                          weak_factory_.GetWeakPtr(), job_id));
       if (info) {
         ++info->inflight_count;
-        delegate_->PreconnectInitiated(info->url, job->url);
+        if (delegate_)
+          delegate_->PreconnectInitiated(info->url, job->url);
       }
       ++inflight_preresolves_count_;
     } else {
diff --git a/chrome/browser/preferences/BUILD.gn b/chrome/browser/preferences/BUILD.gn
index f06f098b..903dba6 100644
--- a/chrome/browser/preferences/BUILD.gn
+++ b/chrome/browser/preferences/BUILD.gn
@@ -13,6 +13,7 @@
     "android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java",
     "android/java/src/org/chromium/chrome/browser/preferences/KeyPrefix.java",
     "android/java/src/org/chromium/chrome/browser/preferences/PrefChangeRegistrar.java",
+    "android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java",
     "android/java/src/org/chromium/chrome/browser/preferences/SharedPreferencesManager.java",
   ]
   deps = [
@@ -44,7 +45,10 @@
 }
 
 generate_jni("jni_headers") {
-  sources = [ "android/java/src/org/chromium/chrome/browser/preferences/PrefChangeRegistrar.java" ]
+  sources = [
+    "android/java/src/org/chromium/chrome/browser/preferences/PrefChangeRegistrar.java",
+    "android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java",
+  ]
 }
 
 java_library("preferences_junit_tests") {
diff --git a/chrome/browser/preferences/android/README.md b/chrome/browser/preferences/android/README.md
index ac7edf6f..9368c8d 100644
--- a/chrome/browser/preferences/android/README.md
+++ b/chrome/browser/preferences/android/README.md
@@ -10,12 +10,12 @@
 supports reading and writing simple key-value pairs to a file that is saved
 across app sessions.
 
-## PrefService
+## PrefServiceBridge
 
-[`PrefService`][2] is a JNI bridge providing access to a native Chrome
-[PrefService][3] instance associated. This interface can be used to read and
-write prefs once they're registered through the `PrefRegistry` and exposed to
-Java by way of a `java_cpp_strings` build target such as [this one][4].
+[`PrefServiceBridge`][2] is a JNI bridge providing access to the native Chrome
+[PrefService][3] instance associated with the active user profile. This
+interface can be used to read and write prefs once they're registered through
+the `PrefRegistry` and added to the [`@Pref` enum][4].
 
 ## FAQ
 
@@ -33,24 +33,26 @@
 No, then SharedPreferences should be preferred.
 
 **What if the PrefService type I need to access is not supported by
-PrefService (i.e. double, Time, etc.)?**
+PrefServiceBridge (i.e. double, Time, etc.)?**
 
-If a base value type is supported by PrefService, then PrefService should
+If a base value type is supported by PrefService, then PrefServiceBridge should
 be extended to support it once it's needed.
 
 **How do I access a PrefService pref associated with local state rather than
 browser profile?**
 
 Most Chrome for Android preferences should be associated with a specific
-profile. If your preference should instead be associated with [local state][5]
+profile. If your preference should instead be associated with [local state][6]
 (for example, if it is related to the First Run Experience), then you should not
-use PrefService and should instead create your own feature-specific JNI
-bridge to access the correct PrefService instance (see [`first_run_utils.cc`][6]).
+use PrefServiceBridge and should instead create your own feature-specific JNI
+bridge to access the correct PrefService instance (see
+[`first_run_utils.cc`][7]).
 
 [0]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/SharedPreferencesManager.java
 [1]: https://developer.android.com/reference/android/content/SharedPreferences
-[2]: https://source.chromium.org/chromium/chromium/src/+/master:components/prefs/android/java/src/org/chromium/components/prefs/PrefService.java
+[2]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
 [3]: https://chromium.googlesource.com/chromium/src/+/master/services/preferences/README.md
-[4]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/preferences/BUILD.gn;drc=4ae1b7be67cd9b470ebcc90f2747a9f31f155b00;l=28
-[5]: https://www.chromium.org/developers/design-documents/preferences#TOC-Introduction
-[6]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/first_run/android/first_run_utils.cc
+[4]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/android/preferences/prefs.h
+[5]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/preferences/OWNERS
+[6]: https://www.chromium.org/developers/design-documents/preferences#TOC-Introduction
+[7]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/first_run/android/first_run_utils.cc
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
new file mode 100644
index 0000000..260aed0
--- /dev/null
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
@@ -0,0 +1,115 @@
+// 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.
+
+package org.chromium.chrome.browser.preferences;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.annotations.NativeMethods;
+
+/**
+ * PrefServiceBridge is a singleton which provides read and write access to native PrefService.
+ */
+public class PrefServiceBridge {
+    // Singleton constructor. Do not call directly unless for testing purpose.
+    @VisibleForTesting
+    protected PrefServiceBridge() {}
+
+    private static PrefServiceBridge sInstance;
+
+    /**
+     * @return The singleton PrefServiceBridge instance.
+     */
+    public static PrefServiceBridge getInstance() {
+        ThreadUtils.assertOnUiThread();
+        if (sInstance == null) {
+            sInstance = new PrefServiceBridge();
+        }
+        return sInstance;
+    }
+
+    /**
+     * @param preference The name of the preference.
+     */
+    public void clearPref(@NonNull String preference) {
+        PrefServiceBridgeJni.get().clearPref(preference);
+    }
+
+    /**
+     * @param preference The name of the preference.
+     * @return Whether the specified preference is enabled.
+     */
+    public boolean getBoolean(@NonNull String preference) {
+        return PrefServiceBridgeJni.get().getBoolean(preference);
+    }
+
+    /**
+     * @param preference The name of the preference.
+     * @param value The value the specified preference will be set to.
+     */
+    public void setBoolean(@NonNull String preference, boolean value) {
+        PrefServiceBridgeJni.get().setBoolean(preference, value);
+    }
+
+    /**
+     * @param preference The name of the preference.
+     * @return value The value of the specified preference.
+     */
+    public int getInteger(@NonNull String preference) {
+        return PrefServiceBridgeJni.get().getInteger(preference);
+    }
+
+    /**
+     * @param preference The name of the preference.
+     * @param value The value the specified preference will be set to.
+     */
+    public void setInteger(@NonNull String preference, int value) {
+        PrefServiceBridgeJni.get().setInteger(preference, value);
+    }
+
+    /**
+     * @param preference The name of the preference.
+     * @return value The value of the specified preference.
+     */
+    @NonNull
+    public String getString(@NonNull String preference) {
+        return PrefServiceBridgeJni.get().getString(preference);
+    }
+
+    /**
+     * @param preference The name of the preference.
+     * @param value The value the specified preference will be set to.
+     */
+    public void setString(@NonNull String preference, @NonNull String value) {
+        PrefServiceBridgeJni.get().setString(preference, value);
+    }
+
+    /**
+     * @param preference The name of the preference.
+     * @return Whether the specified preference is managed.
+     */
+    public boolean isManagedPreference(@NonNull String preference) {
+        return PrefServiceBridgeJni.get().isManagedPreference(preference);
+    }
+
+    @VisibleForTesting
+    public static void setInstanceForTesting(@Nullable PrefServiceBridge instanceForTesting) {
+        sInstance = instanceForTesting;
+    }
+
+    @NativeMethods
+    interface Natives {
+        void clearPref(String preference);
+        boolean getBoolean(String preference);
+        void setBoolean(String preference, boolean value);
+        int getInteger(String preference);
+        void setInteger(String preference, int value);
+        String getString(String preference);
+        void setString(String preference, String value);
+        boolean isManagedPreference(String preference);
+    }
+}
diff --git a/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.html b/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.html
index 904acf3..18bae8c5 100644
--- a/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.html
+++ b/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.html
@@ -100,7 +100,8 @@
     width: 100%;
   }
 </style>
-<div id="destination-dropdown" on-keydown="onKeyDown_" tabindex="0">
+<div id="destination-dropdown" on-keydown="onKeyDown_" tabindex="0"
+    on-blur="onBlur_" on-click="onClick_">
   <div id="destination-display-container">
     <div id="destination-icon-box">
       <iron-icon icon="[[destinationIcon]]"
@@ -122,7 +123,7 @@
       <div slot="dropdown-content">
         <template is="dom-repeat" items="[[itemList]]">
           <button id="[[item.key]]" tabindex="-1" value="[[item.key]]"
-              on-click="onSelect_"
+              on-click="onSelect_" on-blur="onBlur_"
               class$="list-item [[getHighlightedClass_(item.key,
                   highlightedIndex_)]]">
             <printer-status-icon-cros icon-location="[[IconLocation.DROPDOWN]]"
@@ -134,25 +135,25 @@
           </button>
         </template>
         <button on-click="onSelect_" tabindex="-1" value="[[pdfDestinationKey]]"
-          hidden$="[[pdfPrinterDisabled]]"
+          hidden$="[[pdfPrinterDisabled]]" on-blur="onBlur_"
           class$="list-item [[getHighlightedClass_(pdfDestinationKey,
               highlightedIndex_)]]">
           $i18n{printToPDF}
         </button>
-        <button on-click="onSelect_" tabindex="-1"
+        <button on-click="onSelect_" tabindex="-1" on-blur="onBlur_"
           value="[[driveDestinationKey]]" hidden$="[[!driveDestinationKey]]"
           class$="list-item [[getHighlightedClass_(driveDestinationKey,
               highlightedIndex_)]]">
           $i18n{printToGoogleDrive}
         </button>
         <button on-click="onSelect_" tabindex="-1" value="noDestinations"
-          hidden$="[[!noDestinations]]"
+          hidden$="[[!noDestinations]]" on-blur="onBlur_"
           class$="list-item [[getHighlightedClass_('noDestinations',
               highlightedIndex_)]]">
           $i18n{noDestinationsMessage}
         </button>
         <button on-click="onSelect_" tabindex="-1" value="seeMore"
-          aria-label$="[[i18n(seeMoreDestinationsLabel)]]"
+          aria-label$="[[i18n(seeMoreDestinationsLabel)]]" on-blur="onBlur_"
           class$="list-item [[getHighlightedClass_('seeMore',
               highlightedIndex_)]]">
           $i18n{seeMore}
diff --git a/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.js b/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.js
index 24ac4990..f2c3e89 100644
--- a/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.js
+++ b/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.js
@@ -68,17 +68,10 @@
 
   /** @override */
   attached() {
-    this.pointerDownListener_ = event => this.onPointerDown_(event);
-    document.addEventListener('pointerdown', this.pointerDownListener_);
     this.updateTabIndex_();
     this.IconLocation = IconLocation;
   },
 
-  /** @override */
-  detached() {
-    document.removeEventListener('pointerdown', this.pointerDownListener_);
-  },
-
   /**
    * Enqueues a task to refit the iron-dropdown if it is open.
    * @private
@@ -130,28 +123,20 @@
     this.highlightedIndex_ = this.getButtonListFromDropdown_().indexOf(item);
   },
 
-  /**
-   * @param {!Event} event
-   * @private
-   */
-  onPointerDown_(event) {
-    const paths = event.composedPath();
+  /** @private */
+  onClick_(event) {
     const dropdown =
         /** @type {!IronDropdownElement} */ (this.$$('iron-dropdown'));
-    const destinationDropdown =
-        /** @type {!Element} */ (this.$$('#destination-dropdown'));
-
     // Exit if path includes |dropdown| because event will be handled by
     // onSelect_.
-    if (paths.includes(dropdown)) {
+    if (event.composedPath().includes(dropdown)) {
       return;
     }
 
-    if (!paths.includes(destinationDropdown) || dropdown.opened) {
+    if (dropdown.opened) {
       this.closeDropdown_();
       return;
     }
-
     this.openDropdown_();
   },
 
@@ -171,9 +156,6 @@
     event.stopPropagation();
     const dropdown = this.$$('iron-dropdown');
     switch (event.code) {
-      case 'Tab':
-        this.closeDropdown_();
-        break;
       case 'ArrowUp':
       case 'ArrowDown':
         this.onArrowKeyPress_(event.code);
@@ -307,4 +289,17 @@
         'highlighted' :
         '';
   },
+
+  /**
+   * Close the dropdown when focus is lost except when an item in the dropdown
+   * is the element that received the focus.
+   * @param {!Event} event
+   * @private
+   */
+  onBlur_(event) {
+    if (!this.getButtonListFromDropdown_().includes(
+            /** @type {!Element} */ (event.relatedTarget))) {
+      this.closeDropdown_();
+    }
+  },
 });
diff --git a/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.html b/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.html
index bea9c3c..eae831f4 100644
--- a/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.html
+++ b/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.html
@@ -29,7 +29,8 @@
         </cr-input>
         <cr-input id="passwordInput" value="[[item.password]]"
             class="password-input" label="$i18n{editPasswordPasswordLabel}"
-            type="[[getPasswordInputType_(visible)]]">
+            type="[[getPasswordInputType_(visible)]]" required auto-validate
+            invalid="{{inputInvalid_}}">
           <cr-icon-button id="showPasswordButton"
               class$="[[showPasswordIcon_(visible)]]"
               slot="suffix" on-click="onShowPasswordButtonClick_"
@@ -42,7 +43,8 @@
         <cr-button id="cancel" class="cancel-button" on-click="onCancel_">
           $i18n{cancel}
         </cr-button>
-        <cr-button id="save" class="action-button" on-click="onSave_">
+        <cr-button id="save" class="action-button" on-click="onSave_"
+             disabled="[[inputInvalid_]]">
           $i18n{save}
         </cr-button>
       </div>
diff --git a/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.js b/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.js
index 0e18db6..1c25550 100644
--- a/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.js
+++ b/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.js
@@ -48,6 +48,12 @@
       type: Boolean,
       value: false,
     },
+
+    /**
+     * Whether the input is invalid.
+     * @private
+     */
+    inputInvalid_: Boolean,
   },
 
   /** @private {?PasswordManagerProxy} */
@@ -84,7 +90,7 @@
     this.passwordManager_
         .changeCompromisedCredential(
             assert(this.item), this.$.passwordInput.value)
-        .then(() => {
+        .finally(() => {
           this.close();
         });
   },
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_section.js b/chrome/browser/resources/settings/autofill_page/passwords_section.js
index fe52381493..9c4287a 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_section.js
+++ b/chrome/browser/resources/settings/autofill_page/passwords_section.js
@@ -138,7 +138,8 @@
     eligibleForAccountStorage_: {
       type: Boolean,
       value: false,
-      computed: 'computeEligibleForAccountStorage_(syncStatus_, signedIn_)',
+      computed: 'computeEligibleForAccountStorage_(' +
+          'syncStatus_, signedIn_, syncPrefs_)',
     },
 
     /** @private */
@@ -375,8 +376,8 @@
     this.addWebUIListener('sync-status-changed', syncStatusChanged);
 
     const syncPrefsChanged = syncPrefs => this.syncPrefs_ = syncPrefs;
-    syncBrowserProxy.sendSyncPrefsChanged();
     this.addWebUIListener('sync-prefs-changed', syncPrefsChanged);
+    syncBrowserProxy.sendSyncPrefsChanged();
 
     // For non-ChromeOS, also check whether accounts are available.
     // <if expr="not chromeos">
@@ -461,10 +462,13 @@
    * @private
    */
   computeEligibleForAccountStorage_() {
-    // |this.syncStatus_.signedIn| means the user has sync enabled, while
-    // |this.signedIn_| means they have signed in, in the content area.
+    // The user must have signed in but should have sync disabled
+    // (|!this.syncStatus_.signedin|). They should not be using a custom
+    // passphrase to encrypt their sync data, since there's no way for account
+    // storage users to input their passphrase and decrypt the passwords.
     return this.accountStorageFeatureEnabled_ &&
-        (!!this.syncStatus_ && !this.syncStatus_.signedIn) && this.signedIn_;
+        (!!this.syncStatus_ && !this.syncStatus_.signedIn) && this.signedIn_ &&
+        (!this.syncPrefs_ || !this.syncPrefs_.encryptAllData);
   },
 
   /**
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.html b/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.html
index 80a8df3..81c6219 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.html
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.html
@@ -1,11 +1,11 @@
-    <style include="settings-shared"></style>
+<style include="settings-shared"></style>
 
-    <cr-dialog id="dialog" close-text="$i18n{close}">
-      <div slot="title">$i18n{historyDeletionDialogTitle}</div>
-      <div slot="body">$i18nRaw{historyDeletionDialogBody}</div>
-      <div slot="button-container">
-        <cr-button class="action-button" on-click="onOkTap_">
-          $i18n{historyDeletionDialogOK}
-        </cr-button>
-      </div>
-    </cr-dialog>
+<cr-dialog id="dialog" close-text="$i18n{close}" show-on-attach>
+  <div slot="title">$i18n{historyDeletionDialogTitle}</div>
+  <div slot="body">$i18nRaw{historyDeletionDialogBody}</div>
+  <div slot="button-container">
+    <cr-button class="action-button" on-click="onOkClick_">
+      $i18n{historyDeletionDialogOK}
+    </cr-button>
+  </div>
+</cr-dialog>
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.js b/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.js
index 234766e..3d0e1f1 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.js
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.js
@@ -19,16 +19,11 @@
 
   _template: html`{__html_template__}`,
 
-  /** @override */
-  attached() {
-    this.$.dialog.showModal();
-  },
-
   /**
-   * Tap handler for the "OK" button.
+   * Click handler for the "OK" button.
    * @private
    */
-  onOkTap_() {
+  onOkClick_() {
     this.$.dialog.close();
   },
 });
diff --git a/chrome/browser/resources/signin/dice_web_signin_intercept/dice_web_signin_intercept.html b/chrome/browser/resources/signin/dice_web_signin_intercept/dice_web_signin_intercept.html
index b9a1ff69..d2dfd14 100644
--- a/chrome/browser/resources/signin/dice_web_signin_intercept/dice_web_signin_intercept.html
+++ b/chrome/browser/resources/signin/dice_web_signin_intercept/dice_web_signin_intercept.html
@@ -2,6 +2,20 @@
 <html dir="$i18n{textdirection}" lang="$i18n{language}">
   <head>
     <meta charset="utf-8">
+    <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
+    <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
+    <style>
+      body {
+        height: 100vh;
+        margin: 0;
+        width: 100vw;
+      }
+      @media (prefers-color-scheme: dark) {
+        body {
+          background-color: var(--md-background-color);
+        }
+      }
+    </style>
   </head>
   <body>
     <dice-web-signin-intercept-app></dice-web-signin-intercept-app>
diff --git a/chrome/browser/resources/signin/dice_web_signin_intercept/dice_web_signin_intercept_app.html b/chrome/browser/resources/signin/dice_web_signin_intercept/dice_web_signin_intercept_app.html
index 95dfaa3c..e86eb02 100644
--- a/chrome/browser/resources/signin/dice_web_signin_intercept/dice_web_signin_intercept_app.html
+++ b/chrome/browser/resources/signin/dice_web_signin_intercept/dice_web_signin_intercept_app.html
@@ -1,13 +1,53 @@
-<div>
-  <h1>$i18n{diceWebSigninInterceptTitle}</h1>
+<style include="signin-dialog-shared">
+  :host {
+    color: var(--cr-primary-text-color);
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+  }
+
+  #header {
+    /**
+     * TODO(crbug.com/1076880): replace the hardcoded background color with the
+     * browser-provided one.
+     */
+    background-color: rgb(206, 234, 214);
+    border-radius: 8px;
+    margin: 8px;
+    min-height: 128px;
+  }
+
+  #body {
+    flex-grow: 1;
+    font-size: 13px;
+    line-height: 20px;
+    margin: 0 16px;
+  }
+
+  #title {
+    font-size: 15px;
+    font-weight: 500;
+    line-height: 22px;
+    margin: 0 0 8px;
+  }
+
+  cr-button {
+    font-size: 12px;
+  }
+</style>
+<div id="header"></div>
+
+<div id="body">
+  <div id="title">$i18n{diceWebSigninInterceptTitle}</div>
   <div>$i18n{diceWebSigninInterceptDesc}</div>
 </div>
-<div>
-  <cr-button id="cancelButton" on-click="onCancel_">
-    $i18n{diceWebSigninInterceptCancelLabel}
-  </cr-button>
+
+<div class="action-container">
   <cr-button id="acceptButton" class="action-button" on-click="onAccept_"
       autofocus>
     $i18n{diceWebSigninInterceptAcceptLabel}
   </cr-button>
+  <cr-button id="cancelButton" on-click="onCancel_">
+    $i18n{diceWebSigninInterceptCancelLabel}
+  </cr-button>
 </div>
diff --git a/chrome/browser/resources/signin/dice_web_signin_intercept/dice_web_signin_intercept_app.js b/chrome/browser/resources/signin/dice_web_signin_intercept/dice_web_signin_intercept_app.js
index aa425c84..1bd902bf8 100644
--- a/chrome/browser/resources/signin/dice_web_signin_intercept/dice_web_signin_intercept_app.js
+++ b/chrome/browser/resources/signin/dice_web_signin_intercept/dice_web_signin_intercept_app.js
@@ -4,6 +4,7 @@
 
 import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
 import './strings.m.js';
+import './signin_shared_css.js';
 
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
diff --git a/chrome/browser/resources/signin/profile_picker/BUILD.gn b/chrome/browser/resources/signin/profile_picker/BUILD.gn
index 20917e62..d25ff689 100644
--- a/chrome/browser/resources/signin/profile_picker/BUILD.gn
+++ b/chrome/browser/resources/signin/profile_picker/BUILD.gn
@@ -69,5 +69,6 @@
     "profile_picker_app.js",
     "profile_picker_main_view.js",
     "profile_card.js",
+    "profile_picker_shared_css.js",
   ]
 }
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_app.html b/chrome/browser/resources/signin/profile_picker/profile_picker_app.html
index baab767..e688916e6 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_app.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_app.html
@@ -1,4 +1,4 @@
-<style>
+<style include="profile-picker-shared">
   cr-view-manager {
     display: flex;
     font-size: 100%;
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_app.js b/chrome/browser/resources/signin/profile_picker/profile_picker_app.js
index de201ded..ad7f08e 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_app.js
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_app.js
@@ -5,6 +5,7 @@
 import 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.m.js';
 import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.m.js';
 import './profile_picker_main_view.js';
+import './profile_picker_shared_css.js';
 
 import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
index 7d55024..023267f 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
@@ -1,4 +1,4 @@
-<style>
+<style include="profile-picker-shared">
   :host {
     --avatar-icon-size: 74px;
     --banner-img-height: 628px;
@@ -26,6 +26,11 @@
     right: 0;
   }
 
+  .title-container {
+    margin: 30px auto;
+    text-align: center;
+  }
+
   .profiles-container {
     --grid-gutter: 24px;
     --profile-item-height:178px;
@@ -92,6 +97,14 @@
 </style>
 
 <div id="leftBanner" class="banner"></div>
+<div class="title-container">
+  <img id="product-logo" on-click="onProductLogoTap_"
+      srcset="chrome://theme/current-channel-logo@1x 1x,
+              chrome://theme/current-channel-logo@2x 2x"
+      role="presentation">
+  <h2>$i18n{mainViewTitle}</h2>
+  <h3>$i18n{mainViewSubtitle}</h3>
+</div>
 <div class="profiles-container">
   <template is="dom-repeat"
       hidden="[[!profilesList_]]" items="[[profilesList_]]">
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.js b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.js
index 06c8708..b1ec2b7f0 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.js
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.js
@@ -6,6 +6,7 @@
 import 'chrome://resources/cr_elements/shared_vars_css.m.js';
 import './icons.js';
 import './profile_card.js';
+import './profile_picker_shared_css.js';
 
 import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -47,6 +48,18 @@
     this.manageProfilesBrowserProxy_.initializeMainView();
   },
 
+  /** @private */
+  onProductLogoTap_() {
+    this.$['product-logo'].animate(
+        {
+          transform: ['none', 'rotate(-10turn)'],
+        },
+        {
+          duration: 500,
+          easing: 'cubic-bezier(1, 0, 0, 1)',
+        });
+  },
+
   /**
    * Handler for when the profiles list are updated.
    * @param {!Array<!ProfileState>} profilesList
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_resources.grd b/chrome/browser/resources/signin/profile_picker/profile_picker_resources.grd
index 194e84cc..dc7acf1 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_resources.grd
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_resources.grd
@@ -21,16 +21,19 @@
     <!-- Generated Polymer 3 elements -->
       <include name="IDR_PROFILE_PICKER_PROFILE_PICKER_MAIN_VIEW_JS"
                file="${root_gen_dir}/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.js"
-               use_base_dir="false" type="BINDATA" preprocess="true"/>
+               use_base_dir="false" type="BINDATA"/>
       <include name="IDR_PROFILE_PICKER_PROFILE_PICKER_APP_JS"
                file="${root_gen_dir}/chrome/browser/resources/signin/profile_picker/profile_picker_app.js"
-               use_base_dir="false" type="BINDATA" preprocess="true"/>
+               use_base_dir="false" type="BINDATA"/>
       <include name="IDR_PROFILE_PICKER_PROFILE_CARD_JS"
                file="${root_gen_dir}/chrome/browser/resources/signin/profile_picker/profile_card.js"
                use_base_dir="false" type="BINDATA" preprocess="true"/>
       <include name="IDR_PROFILE_PICKER_PROFILE_CREATION_FLOW_PROFILE_TYPE_CHOICE_JS"
                file="${root_gen_dir}/chrome/browser/resources/signin/profile_picker/profile_creation_flow/profile_type_choice.js"
                use_base_dir="false" type="BINDATA"/>
+     <include name="IDR_PROFILE_PICKER_PROFILE_PICKER_SHARED_CSS_JS"
+             file="${root_gen_dir}/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.js"
+             use_base_dir="false" type="BINDATA"/>
     </includes>
     <structures>
       <structure
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html b/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html
new file mode 100644
index 0000000..508c280
--- /dev/null
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html
@@ -0,0 +1,8 @@
+<template>
+  <style>
+    h3 {
+      color: var(--google-grey-refresh-700);
+      font-weight: 500;
+    }
+  </style>
+</template>
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.js b/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.js
new file mode 100644
index 0000000..2134465
--- /dev/null
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.js
@@ -0,0 +1,13 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+
+import 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+const template = document.createElement('template');
+template.innerHTML = `
+<dom-module id="profile-picker-shared">{__html_template__}</dom-module>
+`;
+document.body.appendChild(template.content.cloneNode(true));
diff --git a/chrome/browser/sharesheet/sharesheet_service.cc b/chrome/browser/sharesheet/sharesheet_service.cc
index 6fcf2477..3627518 100644
--- a/chrome/browser/sharesheet/sharesheet_service.cc
+++ b/chrome/browser/sharesheet/sharesheet_service.cc
@@ -39,10 +39,17 @@
 }
 
 // Cleanup delegate when bubble closes.
-void SharesheetService::OnBubbleClosed(uint32_t id) {
+void SharesheetService::OnBubbleClosed(uint32_t id,
+                                       const base::string16& active_action) {
   auto iter = active_delegates_.begin();
   while (iter != active_delegates_.end()) {
     if ((*iter)->GetId() == id) {
+      if (!active_action.empty()) {
+        ShareAction* share_action =
+            sharesheet_action_cache_->GetActionFromName(active_action);
+        if (share_action != nullptr)
+          share_action->OnClosing(iter->get());
+      }
       active_delegates_.erase(iter);
       break;
     }
@@ -50,4 +57,35 @@
   }
 }
 
+void SharesheetService::OnTargetSelected(uint32_t delegate_id,
+                                         const base::string16& target_name,
+                                         const TargetType type,
+                                         views::View* share_action_view) {
+  if (type == TargetType::kAction) {
+    ShareAction* share_action =
+        sharesheet_action_cache_->GetActionFromName(target_name);
+    if (share_action == nullptr)
+      return;
+
+    SharesheetServiceDelegate* delegate = GetDelegate(delegate_id);
+    if (delegate == nullptr)
+      return;
+
+    delegate->OnActionLaunched();
+    share_action->LaunchAction(delegate, share_action_view);
+  }
+}
+
+SharesheetServiceDelegate* SharesheetService::GetDelegate(
+    uint32_t delegate_id) {
+  auto iter = active_delegates_.begin();
+  while (iter != active_delegates_.end()) {
+    if ((*iter)->GetId() == delegate_id) {
+      return iter->get();
+    }
+    ++iter;
+  }
+  return nullptr;
+}
+
 }  // namespace sharesheet
diff --git a/chrome/browser/sharesheet/sharesheet_service.h b/chrome/browser/sharesheet/sharesheet_service.h
index 0c5606b..cf850f26 100644
--- a/chrome/browser/sharesheet/sharesheet_service.h
+++ b/chrome/browser/sharesheet/sharesheet_service.h
@@ -8,7 +8,9 @@
 #include <memory>
 #include <vector>
 
+#include "base/strings/string16.h"
 #include "chrome/browser/sharesheet/sharesheet_action_cache.h"
+#include "chrome/browser/sharesheet/sharesheet_types.h"
 #include "components/keyed_service/core/keyed_service.h"
 
 class Profile;
@@ -32,7 +34,12 @@
   SharesheetService& operator=(const SharesheetService&) = delete;
 
   void ShowBubble(views::View* bubble_anchor_view);
-  void OnBubbleClosed(uint32_t id);
+  void OnBubbleClosed(uint32_t id, const base::string16& active_action);
+  void OnTargetSelected(uint32_t delegate_id,
+                        const base::string16& target_name,
+                        const TargetType type,
+                        views::View* share_action_view);
+  SharesheetServiceDelegate* GetDelegate(uint32_t delegate_id);
 
  private:
   uint32_t delegate_counter_ = 0;
diff --git a/chrome/browser/sharesheet/sharesheet_service_delegate.cc b/chrome/browser/sharesheet/sharesheet_service_delegate.cc
index 46d2b0e..67b8a9ae 100644
--- a/chrome/browser/sharesheet/sharesheet_service_delegate.cc
+++ b/chrome/browser/sharesheet/sharesheet_service_delegate.cc
@@ -30,9 +30,22 @@
   sharesheet_bubble_view_->ShowBubble(std::move(targets));
 }
 
-void SharesheetServiceDelegate::OnBubbleClosed() {
+void SharesheetServiceDelegate::OnBubbleClosed(
+    const base::string16& active_action) {
   sharesheet_bubble_view_.release();
-  sharesheet_service_->OnBubbleClosed(id_);
+  sharesheet_service_->OnBubbleClosed(id_, active_action);
+}
+
+void SharesheetServiceDelegate::OnTargetSelected(
+    const base::string16& target_name,
+    const TargetType type,
+    views::View* share_action_view) {
+  sharesheet_service_->OnTargetSelected(id_, target_name, type,
+                                        share_action_view);
+}
+
+void SharesheetServiceDelegate::OnActionLaunched() {
+  sharesheet_bubble_view_->ShowActionView();
 }
 
 uint32_t SharesheetServiceDelegate::GetId() {
diff --git a/chrome/browser/sharesheet/sharesheet_service_delegate.h b/chrome/browser/sharesheet/sharesheet_service_delegate.h
index 3fed3e2d..dec5933 100644
--- a/chrome/browser/sharesheet/sharesheet_service_delegate.h
+++ b/chrome/browser/sharesheet/sharesheet_service_delegate.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/strings/string16.h"
 #include "chrome/browser/sharesheet/sharesheet_controller.h"
 #include "chrome/browser/sharesheet/sharesheet_types.h"
 
@@ -33,7 +34,11 @@
       delete;
 
   void ShowBubble(std::vector<TargetInfo> targets);
-  void OnBubbleClosed();
+  void OnBubbleClosed(const base::string16& active_action);
+  void OnTargetSelected(const base::string16& target_name,
+                        const TargetType type,
+                        views::View* share_action_view);
+  void OnActionLaunched();
 
   // SharesheetController overrides
   uint32_t GetId() override;
@@ -41,6 +46,7 @@
 
  private:
   const uint32_t id_;
+  base::string16 active_action_;
   std::unique_ptr<SharesheetBubbleView> sharesheet_bubble_view_;
   SharesheetService* sharesheet_service_;
 };
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 4edf8eb..d0aa5fb7 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -1438,6 +1438,9 @@
       <message name="IDS_SYNC_SETTINGS" desc="Title for preference which enables sync'ing of settings. [CHAR-LIMT=32]">
         Settings
       </message>
+      <message name="IDS_TURN_OFF_SYNC" desc="Button that user can press to turn off sync and sign out. [CHAR-LIMT=32]">
+        Sign out and turn off sync
+      </message>
       <message name="IDS_SYNC_PAYMENTS_INTEGRATION" desc="Title for preference which enables import of Google Pay data for Autofill. 'Google Pay' should not be translated as it is the product name.">
         Credit cards and addresses using Google Pay
       </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_TURN_OFF_SYNC.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_TURN_OFF_SYNC.png.sha1
new file mode 100644
index 0000000..64bfc87
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_TURN_OFF_SYNC.png.sha1
@@ -0,0 +1 @@
+635b9fa291786e0e5ac3ce2d5ac2a0022f42aed1
\ No newline at end of file
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index ac3ccf1..37836b0 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -1152,24 +1152,6 @@
   }
 }
 
-// Test that get_process_idle_time() returns reasonable values when compared
-// with time deltas measured locally.
-IN_PROC_BROWSER_TEST_F(BrowserTest, RenderIdleTime) {
-  base::TimeTicks start = base::TimeTicks::Now();
-  ui_test_utils::NavigateToURL(
-      browser(), ui_test_utils::GetTestUrl(
-                     base::FilePath(base::FilePath::kCurrentDirectory),
-                     base::FilePath(kTitle1File)));
-  base::TimeDelta renderer_td = browser()
-                                    ->tab_strip_model()
-                                    ->GetActiveWebContents()
-                                    ->GetMainFrame()
-                                    ->GetProcess()
-                                    ->GetChildProcessIdleTime();
-  base::TimeDelta browser_td = base::TimeTicks::Now() - start;
-  EXPECT_TRUE(browser_td >= renderer_td);
-}
-
 // Test RenderView correctly send back favicon url for web page that redirects
 // to an anchor in javascript body.onload handler.
 IN_PROC_BROWSER_TEST_F(BrowserTest,
diff --git a/chrome/browser/ui/views/extensions/extension_popup.cc b/chrome/browser/ui/views/extensions/extension_popup.cc
index 0d3fa1e..7d96b50 100644
--- a/chrome/browser/ui/views/extensions/extension_popup.cc
+++ b/chrome/browser/ui/views/extensions/extension_popup.cc
@@ -128,12 +128,17 @@
     content::BrowserContext* browser_context,
     const extensions::Extension* extension,
     extensions::UnloadedExtensionReason reason) {
+  CHECK(host_);
   if (extension->id() == host_->extension_id()) {
     // To ensure |extension_view_| cannot receive any messages that cause it to
     // try to access the host during Widget closure, destroy it immediately.
     RemoveChildViewT(extension_view_);
 
     host_.reset();
+    // Stop observing the registry immediately to prevent any subsequent
+    // notifications, since Widget::Close is asynchronous.
+    extension_registry_observer_.RemoveAll();
+
     GetWidget()->Close();
   }
 }
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
index f50d405..93df095 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
@@ -201,13 +201,20 @@
           container->GetViewForId(extensions()[0]->id())->GetVisible());
     }
   }
+
   void TriggerSingleExtensionButton() {
+    ASSERT_EQ(1u, GetExtensionsMenuItemViews().size());
+    TriggerExtensionButton(0u);
+  }
+
+  void TriggerExtensionButton(size_t item_index) {
     auto menu_items = GetExtensionsMenuItemViews();
-    ASSERT_EQ(1u, menu_items.size());
+    ASSERT_LT(item_index, menu_items.size());
+
     ui::MouseEvent click_event(ui::ET_MOUSE_RELEASED, gfx::Point(),
                                gfx::Point(), base::TimeTicks(),
                                ui::EF_LEFT_MOUSE_BUTTON, 0);
-    menu_items[0]
+    menu_items[item_index]
         ->primary_action_button_for_testing()
         ->button_controller()
         ->OnMouseReleased(click_event);
@@ -477,6 +484,33 @@
   EXPECT_TRUE(GetVisibleToolbarActionViews().empty());
 }
 
+// Test for crbug.com/1099456.
+IN_PROC_BROWSER_TEST_F(ExtensionsMenuViewBrowserTest,
+                       RemoveMultipleExtensionsWhileShowingPopup) {
+  auto& id1 = LoadTestExtension("extensions/simple_with_popup")->id();
+  auto& id2 = LoadTestExtension("extensions/uitest/window_open")->id();
+  ShowUi("");
+  VerifyUi();
+  TriggerExtensionButton(0u);
+
+  ExtensionsContainer* const extensions_container =
+      BrowserView::GetBrowserViewForBrowser(browser())
+          ->toolbar()
+          ->extensions_container();
+  ASSERT_NE(nullptr, extensions_container->GetPoppedOutAction());
+
+  auto* extension_service =
+      extensions::ExtensionSystem::Get(browser()->profile())
+          ->extension_service();
+
+  extension_service->DisableExtension(
+      id1, extensions::disable_reason::DISABLE_USER_ACTION);
+  extension_service->DisableExtension(
+      id2, extensions::disable_reason::DISABLE_USER_ACTION);
+
+  EXPECT_EQ(nullptr, extensions_container->GetPoppedOutAction());
+}
+
 IN_PROC_BROWSER_TEST_F(ExtensionsMenuViewBrowserTest,
                        TriggeringExtensionClosesMenu) {
   LoadTestExtension("extensions/trigger_actions/browser_action");
diff --git a/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view.cc b/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view.cc
index c2cd93f8..0e1afa4d 100644
--- a/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view.cc
+++ b/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view.cc
@@ -25,7 +25,7 @@
 #include "ui/views/widget/widget.h"
 
 namespace {
-constexpr int kInterceptionBubbleHeight = 362;
+constexpr int kInterceptionBubbleHeight = 342;
 constexpr int kInterceptionBubbleWidth = 290;
 }  // namespace
 
diff --git a/chrome/browser/ui/views/sharesheet_bubble_view.cc b/chrome/browser/ui/views/sharesheet_bubble_view.cc
index 0278e17..20a72526 100644
--- a/chrome/browser/ui/views/sharesheet_bubble_view.cc
+++ b/chrome/browser/ui/views/sharesheet_bubble_view.cc
@@ -6,11 +6,17 @@
 
 #include <utility>
 
+#include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/sharesheet/sharesheet_service_delegate.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/button/image_button_factory.h"
+#include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/styled_label.h"
 #include "ui/views/layout/box_layout.h"
@@ -18,12 +24,54 @@
 
 namespace {
 
-constexpr int kColumnSetIdTitle = 0;
-constexpr int kVerticalSpacing = 24;
+constexpr int kButtonSize = 64;
+constexpr int kMaxTargetRowSize = 4;
+constexpr int kSpacing = 24;
 constexpr char kTitle[] = "Share";
 
+enum { COLUMN_SET_ID_TITLE, COLUMN_SET_ID_TARGETS };
+
 }  // namespace
 
+// ShareSheetTargetButton
+
+// A button that represents a candidate share target.
+class ShareSheetTargetButton : public views::Button {
+ public:
+  ShareSheetTargetButton(views::ButtonListener* listener,
+                         const base::string16& display_name,
+                         const gfx::Image* icon)
+      : Button(listener) {
+    SetLayoutManager(std::make_unique<views::BoxLayout>(
+        views::BoxLayout::Orientation::kVertical, gfx::Insets(),
+        ChromeLayoutProvider::Get()->GetDistanceMetric(
+            views::DISTANCE_RELATED_CONTROL_VERTICAL)));
+
+    auto* image = AddChildView(std::make_unique<views::ImageView>());
+    image->set_can_process_events_within_subtree(false);
+
+    if (!icon->IsEmpty()) {
+      image->SetImage(*icon->ToImageSkia());
+    }
+
+    auto* label = AddChildView(std::make_unique<views::Label>(display_name));
+    label->SetBackgroundColor(SK_ColorTRANSPARENT);
+    label->SetHandlesTooltips(false);
+    label->SetMultiLine(true);
+    label->SetAutoColorReadabilityEnabled(false);
+    label->SetHorizontalAlignment(gfx::ALIGN_CENTER);
+
+    SetFocusForPlatform();
+  }
+
+  ShareSheetTargetButton(const ShareSheetTargetButton&) = delete;
+  ShareSheetTargetButton& operator=(const ShareSheetTargetButton&) = delete;
+
+  gfx::Size CalculatePreferredSize() const override {
+    return gfx::Size(kButtonSize, kButtonSize);
+  }
+};
+
 SharesheetBubbleView::SharesheetBubbleView(
     views::View* anchor_view,
     sharesheet::SharesheetServiceDelegate* delegate)
@@ -65,34 +113,82 @@
       main_view_->SetLayoutManager(std::make_unique<views::GridLayout>());
 
   // Set up columnsets
-  views::ColumnSet* cs = main_layout->AddColumnSet(kColumnSetIdTitle);
+  views::ColumnSet* cs = main_layout->AddColumnSet(COLUMN_SET_ID_TITLE);
   cs->AddColumn(/* h_align */ views::GridLayout::FILL,
                 /* v_align */ views::GridLayout::CENTER,
                 /* resize_percent */ 1.0,
                 views::GridLayout::ColumnSize::kUsePreferred,
                 /* fixed_width */ 0, /*min_width*/ 0);
 
+  views::ColumnSet* cs_buttons =
+      main_layout->AddColumnSet(COLUMN_SET_ID_TARGETS);
+  cs_buttons->AddPaddingColumn(/* resize_percent */ 1, kSpacing);
+  cs_buttons->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
+                        1.0, views::GridLayout::ColumnSize::kFixed, kButtonSize,
+                        0);
+  cs_buttons->AddPaddingColumn(/* resize_percent */ 1, kSpacing);
+  cs_buttons->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
+                        1.0, views::GridLayout::ColumnSize::kFixed, kButtonSize,
+                        0);
+  cs_buttons->AddPaddingColumn(/* resize_percent */ 1, kSpacing);
+  cs_buttons->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
+                        1.0, views::GridLayout::ColumnSize::kFixed, kButtonSize,
+                        0);
+  cs_buttons->AddPaddingColumn(/* resize_percent */ 1, kSpacing);
+  cs_buttons->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
+                        1.0, views::GridLayout::ColumnSize::kFixed, kButtonSize,
+                        0);
+  cs_buttons->AddPaddingColumn(/* resize_percent */ 1, kSpacing);
+
   // Add Title label
-  main_layout->AddPaddingRow(views::GridLayout::kFixedSize, kVerticalSpacing);
-  main_layout->StartRow(views::GridLayout::kFixedSize, kColumnSetIdTitle,
-                        /* height */ kVerticalSpacing);
+  main_layout->AddPaddingRow(views::GridLayout::kFixedSize, kSpacing);
+  main_layout->StartRow(views::GridLayout::kFixedSize, COLUMN_SET_ID_TITLE,
+                        /* height */ kSpacing);
   auto* title = main_layout->AddView(std::make_unique<views::Label>(
       base::UTF8ToUTF16(base::StringPiece(kTitle)),
       views::style::CONTEXT_DIALOG_TITLE, views::style::STYLE_PRIMARY));
   title->SetHorizontalAlignment(gfx::ALIGN_CENTER);
 
+  // Add Targets
+  size_t i = 0;
+  for (const auto& target : targets_) {
+    if (i % kMaxTargetRowSize == 0) {
+      main_layout->AddPaddingRow(views::GridLayout::kFixedSize, kSpacing);
+      main_layout->StartRow(views::GridLayout::kFixedSize,
+                            COLUMN_SET_ID_TARGETS);
+    }
+    auto target_view = std::make_unique<ShareSheetTargetButton>(
+        this, target.display_name, &target.icon);
+    target_view->set_tag(i++);
+    main_layout->AddView(std::move(target_view));
+  }
+  main_layout->AddPaddingRow(views::GridLayout::kFixedSize, kSpacing);
+
   views::Widget* widget = views::BubbleDialogDelegateView::CreateBubble(this);
   GetWidget()->GetRootView()->Layout();
   widget->Show();
 }
 
+void SharesheetBubbleView::ShowActionView() {
+  main_view_->SetVisible(false);
+  share_action_view_->SetVisible(true);
+}
+
 void SharesheetBubbleView::CloseBubble() {
   views::Widget* widget = View::GetWidget();
   widget->CloseWithReason(views::Widget::ClosedReason::kAcceptButtonClicked);
 }
 
+void SharesheetBubbleView::ButtonPressed(views::Button* sender,
+                                         const ui::Event& event) {
+  active_target_ = targets_[sender->tag()].launch_name;
+  delegate_->OnTargetSelected(active_target_, targets_[sender->tag()].type,
+                              share_action_view_);
+  RequestFocus();
+}
+
 void SharesheetBubbleView::OnWidgetDestroyed(views::Widget* widget) {
-  delegate_->OnBubbleClosed();
+  delegate_->OnBubbleClosed(active_target_);
 }
 
 gfx::Size SharesheetBubbleView::CalculatePreferredSize() const {
diff --git a/chrome/browser/ui/views/sharesheet_bubble_view.h b/chrome/browser/ui/views/sharesheet_bubble_view.h
index 1c7083d..94d4987 100644
--- a/chrome/browser/ui/views/sharesheet_bubble_view.h
+++ b/chrome/browser/ui/views/sharesheet_bubble_view.h
@@ -9,12 +9,14 @@
 
 #include "chrome/browser/sharesheet/sharesheet_types.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/controls/button/button.h"
 
 namespace sharesheet {
 class SharesheetServiceDelegate;
 }
 
-class SharesheetBubbleView : public views::BubbleDialogDelegateView {
+class SharesheetBubbleView : public views::BubbleDialogDelegateView,
+                             public views::ButtonListener {
  public:
   using TargetInfo = sharesheet::TargetInfo;
 
@@ -25,8 +27,12 @@
   ~SharesheetBubbleView() override;
 
   void ShowBubble(std::vector<TargetInfo> targets);
+  void ShowActionView();
   void CloseBubble();
 
+  // views::ButtonListener overrides
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
   // views::BubbleDialogDelegateView overrides
   gfx::Size CalculatePreferredSize() const override;
   void OnWidgetDestroyed(views::Widget* widget) override;
@@ -35,6 +41,7 @@
   // Owns this class.
   sharesheet::SharesheetServiceDelegate* delegate_;
   std::vector<TargetInfo> targets_;
+  base::string16 active_target_;
 
   views::View* root_view_ = nullptr;
   views::View* main_view_ = nullptr;
diff --git a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.cc b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.cc
index 002d68e..b5dce67 100644
--- a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.cc
+++ b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.cc
@@ -26,6 +26,7 @@
                           IDR_SIGNIN_DICE_WEB_INTERCEPT_APP_JS);
   source->AddResourcePath("dice_web_signin_intercept_browser_proxy.js",
                           IDR_SIGNIN_DICE_WEB_INTERCEPT_BROWSER_PROXY_JS);
+  source->AddResourcePath("signin_shared_css.js", IDR_SIGNIN_SHARED_CSS_JS);
 
   // Localized strings.
   source->UseStringsJs();
diff --git a/chrome/browser/ui/webui/signin/profile_picker_ui.cc b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
index 7a86f88c..ac09d8d 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_ui.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
@@ -8,9 +8,23 @@
 #include "chrome/browser/ui/webui/signin/profile_picker_handler.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/profile_picker_resources.h"
 #include "chrome/grit/profile_picker_resources_map.h"
 #include "content/public/browser/web_ui_data_source.h"
+#include "ui/base/webui/web_ui_util.h"
+
+namespace {
+
+void AddStrings(content::WebUIDataSource* html_source) {
+  static constexpr webui::LocalizedString kLocalizedStrings[] = {
+      {"mainViewTitle", IDS_PROFILE_PICKER_MAIN_VIEW_TITLE},
+      {"mainViewSubtitle", IDS_PROFILE_PICKER_MAIN_VIEW_SUBTITLE},
+  };
+  AddLocalizedStringsBulk(html_source, kLocalizedStrings);
+}
+
+}  // namespace
 
 ProfilePickerUI::ProfilePickerUI(content::WebUI* web_ui)
     : content::WebUIController(web_ui) {
@@ -27,6 +41,7 @@
       base::make_span(kProfilePickerResources, kProfilePickerResourcesSize),
       generated_path, IDR_PROFILE_PICKER_PROFILE_PICKER_HTML);
 
+  AddStrings(html_source);
   content::WebUIDataSource::Add(profile, html_source);
 }
 
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 85ab78e..db62691 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1595289228-e5c2a2241b190531533d778f2dcf9ff98ced1901.profdata
+chrome-mac-master-1595330901-a1487ea0e73c84091ecbf3f0440329cfe99905ef.profdata
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 5d975e5..83c7e15 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -124,8 +124,6 @@
     "pdf_util.h",
     "pref_names_util.cc",
     "pref_names_util.h",
-    "prerender_url_loader_throttle.cc",
-    "prerender_url_loader_throttle.h",
     "ref_counted_util.h",
     "render_messages.h",
     "search/instant_mojom_traits.h",
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
index c35fa9d7..3e44aa1 100644
--- a/chrome/renderer/BUILD.gn
+++ b/chrome/renderer/BUILD.gn
@@ -92,8 +92,6 @@
     "plugins/pdf_plugin_placeholder.h",
     "plugins/plugin_uma.cc",
     "plugins/plugin_uma.h",
-    "prerender/prerender_helper.cc",
-    "prerender/prerender_helper.h",
     "prerender/prerender_observer.h",
     "prerender/prerender_observer_list.cc",
     "prerender/prerender_observer_list.h",
@@ -159,6 +157,7 @@
     "//components/page_load_metrics/renderer",
     "//components/paint_preview/buildflags",
     "//components/plugins/renderer",
+    "//components/prerender/renderer",
     "//components/resources:components_resources",
     "//components/safe_browsing:buildflags",
     "//components/safe_browsing/content/renderer:throttles",
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 018bffa3..7330a66 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -34,7 +34,6 @@
 #include "chrome/common/crash_keys.h"
 #include "chrome/common/pdf_util.h"
 #include "chrome/common/pepper_permission_util.h"
-#include "chrome/common/prerender_url_loader_throttle.h"
 #include "chrome/common/privacy_budget/privacy_budget_settings_provider.h"
 #include "chrome/common/profiler/thread_profiler.h"
 #include "chrome/common/render_messages.h"
@@ -60,7 +59,6 @@
 #include "chrome/renderer/plugins/pdf_plugin_placeholder.h"
 #include "chrome/renderer/plugins/plugin_preroller.h"
 #include "chrome/renderer/plugins/plugin_uma.h"
-#include "chrome/renderer/prerender/prerender_helper.h"
 #include "chrome/renderer/prerender/prerenderer_client.h"
 #include "chrome/renderer/previews/resource_loading_hints_agent.h"
 #include "chrome/renderer/sync_encryption_keys_extension.h"
@@ -90,7 +88,9 @@
 #include "components/page_load_metrics/renderer/metrics_render_frame_observer.h"
 #include "components/paint_preview/buildflags/buildflags.h"
 #include "components/pdf/renderer/pepper_pdf_host.h"
+#include "components/prerender//common/prerender_url_loader_throttle.h"
 #include "components/prerender/common/prerender_types.mojom.h"
+#include "components/prerender/renderer/prerender_helper.h"
 #include "components/safe_browsing/buildflags.h"
 #include "components/safe_browsing/content/renderer/threat_dom_details.h"
 #include "components/spellcheck/spellcheck_buildflags.h"
diff --git a/chrome/renderer/chrome_render_frame_observer.cc b/chrome/renderer/chrome_render_frame_observer.cc
index 971fe93..339d8a6 100644
--- a/chrome/renderer/chrome_render_frame_observer.cc
+++ b/chrome/renderer/chrome_render_frame_observer.cc
@@ -24,11 +24,11 @@
 #include "chrome/common/open_search_description_document_handler.mojom.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/renderer/media/media_feeds.h"
-#include "chrome/renderer/prerender/prerender_helper.h"
 #include "chrome/renderer/prerender/prerender_observer_list.h"
 #include "chrome/renderer/web_apps.h"
 #include "components/crash/core/common/crash_key.h"
 #include "components/offline_pages/buildflags/buildflags.h"
+#include "components/prerender/renderer/prerender_helper.h"
 #include "components/translate/content/renderer/translate_agent.h"
 #include "components/translate/core/common/translate_util.h"
 #include "components/web_cache/renderer/web_cache_impl.h"
diff --git a/chrome/renderer/prerender/prerenderer_client.cc b/chrome/renderer/prerender/prerenderer_client.cc
index 76c809f..7afb98b 100644
--- a/chrome/renderer/prerender/prerenderer_client.cc
+++ b/chrome/renderer/prerender/prerenderer_client.cc
@@ -5,7 +5,7 @@
 #include "chrome/renderer/prerender/prerenderer_client.h"
 
 #include "base/logging.h"
-#include "chrome/renderer/prerender/prerender_helper.h"
+#include "components/prerender/renderer/prerender_helper.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_view.h"
 #include "third_party/blink/public/web/web_view.h"
diff --git a/chrome/renderer/url_loader_throttle_provider_impl.cc b/chrome/renderer/url_loader_throttle_provider_impl.cc
index 8a4536d..d179bc04 100644
--- a/chrome/renderer/url_loader_throttle_provider_impl.cc
+++ b/chrome/renderer/url_loader_throttle_provider_impl.cc
@@ -17,9 +17,9 @@
 #include "chrome/renderer/chrome_render_frame_observer.h"
 #include "chrome/renderer/chrome_render_thread_observer.h"
 #include "chrome/renderer/lite_video/lite_video_url_loader_throttle.h"
-#include "chrome/renderer/prerender/prerender_helper.h"
 #include "chrome/renderer/subresource_redirect/subresource_redirect_params.h"
 #include "chrome/renderer/subresource_redirect/subresource_redirect_url_loader_throttle.h"
+#include "components/prerender/renderer/prerender_helper.h"
 #include "components/safe_browsing/content/renderer/renderer_url_loader_throttle.h"
 #include "components/safe_browsing/core/features.h"
 #include "content/public/common/content_features.h"
diff --git a/chrome/services/sharing/BUILD.gn b/chrome/services/sharing/BUILD.gn
index 29953ab7..f8277ee 100644
--- a/chrome/services/sharing/BUILD.gn
+++ b/chrome/services/sharing/BUILD.gn
@@ -31,6 +31,7 @@
 
   deps = [
     ":sharing",
+    "nearby",
     "nearby/test_support",
     "webrtc/test",
     "//base/test:test_support",
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index c574bbc..6a1b333 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -221,6 +221,7 @@
   ~TestingProfile() override;
 
   // Creates the favicon service. Consequent calls would recreate the service.
+  // TODO(crbug.com/1106699): Remove this API and adopt the Builder instead.
   void CreateFaviconService();
 
   // !!!!!!!! WARNING: THIS IS GENERALLY NOT SAFE TO CALL! !!!!!!!!
@@ -236,6 +237,7 @@
   // only matters if you're recreating the HistoryService.  If |no_db| is true,
   // the history backend will fail to initialize its database; this is useful
   // for testing error conditions. Returns true on success.
+  // TODO(crbug.com/1106699): Remove this API and adopt the Builder instead.
   bool CreateHistoryService(bool delete_file, bool no_db) WARN_UNUSED_RESULT;
 
   // Creates the BookmarkBarModel. If not invoked the bookmark bar model is
@@ -246,9 +248,14 @@
   //
   // NOTE: this does not block until the bookmarks are loaded. For that use
   // WaitForBookmarkModelToLoad().
+  //
+  // DEPRECATED: Use Builder::AddTestingProfile() together with
+  // BookmarkModelFactory::GetDefaultFactory() in new code.
+  // TODO(crbug.com/1106699): Remove this API and adopt the Builder instead.
   void CreateBookmarkModel(bool delete_file);
 
   // Creates a WebDataService. If not invoked, the web data service is NULL.
+  // TODO(crbug.com/1106699): Remove this API and adopt the Builder instead.
   void CreateWebDataService();
 
   // Blocks until the HistoryService finishes restoring its in-memory cache.
diff --git a/chrome/test/data/extensions/api_test/passwords_private/test.js b/chrome/test/data/extensions/api_test/passwords_private/test.js
index 12e0af50..174d084 100644
--- a/chrome/test/data/extensions/api_test/passwords_private/test.js
+++ b/chrome/test/data/extensions/api_test/passwords_private/test.js
@@ -351,6 +351,27 @@
         });
   },
 
+  function changeCompromisedCredentialWithEmptyPasswordFails() {
+    chrome.passwordsPrivate.changeCompromisedCredential(
+        {
+          id: 0,
+          formattedOrigin: 'example.com',
+          detailedOrigin: 'https://example.com',
+          isAndroidCredential: false,
+          signonRealm: 'https://example.com',
+          username: 'alice',
+          compromiseTime: COMPROMISE_TIME,
+          elapsedTimeSinceCompromise: '3 days ago',
+          compromiseType: 'LEAKED',
+        },
+        '', () => {
+          chrome.test.assertLastError(
+              'Could not change the compromised credential. The new password ' +
+              'can\'t be empty.');
+          chrome.test.succeed();
+        });
+  },
+
   function changeCompromisedCredentialFails() {
     chrome.passwordsPrivate.changeCompromisedCredential(
         {
diff --git a/chrome/test/data/webui/print_preview/destination_dropdown_cros_test.js b/chrome/test/data/webui/print_preview/destination_dropdown_cros_test.js
index 8198689..4a093e9 100644
--- a/chrome/test/data/webui/print_preview/destination_dropdown_cros_test.js
+++ b/chrome/test/data/webui/print_preview/destination_dropdown_cros_test.js
@@ -20,7 +20,6 @@
 destination_dropdown_cros_test.TestNames = {
   CorrectListItems: 'correct list items',
   ClickCloses: 'click closes dropdown',
-  TabCloses: 'tab closes dropdown',
   HighlightedAfterUpDown: 'highlighted after keyboard press up and down',
   DestinationChangeAfterUpDown:
       'destination changes after keyboard press up and down',
@@ -48,22 +47,17 @@
   }
 
   function clickDropdown() {
-    dropdown.$$('#destination-dropdown')
-        .dispatchEvent(new PointerEvent('pointerdown', {
-          bubbles: true,
-          cancelable: true,
-          composed: true,
-          buttons: 1,
-        }));
+    dropdown.$$('#destination-dropdown').click();
+  }
+
+  function clickDropdownFocus() {
+    dropdown.$$('#destination-dropdown').click();
+    dropdown.$$('#destination-dropdown').focus();
   }
 
   function clickOutsideDropdown() {
-    document.body.dispatchEvent(new PointerEvent('pointerdown', {
-      bubbles: true,
-      cancelable: true,
-      composed: true,
-      buttons: 1,
-    }));
+    document.body.click();
+    dropdown.$$('#destination-dropdown').blur();
   }
 
   function down() {
@@ -79,10 +73,6 @@
     keyDownOn(dropdown.$$('#destination-dropdown'), 'Enter', [], 'Enter');
   }
 
-  function tab() {
-    keyDownOn(dropdown.$$('#destination-dropdown'), 'Tab', [], 'Tab');
-  }
-
   /** @return {?Element} */
   function getHighlightedElement() {
     return dropdown.$$('.highlighted');
@@ -140,33 +130,21 @@
         dropdown.value = destinationOne;
         const ironDropdown = dropdown.$$('iron-dropdown');
 
-        clickDropdown();
+        clickDropdownFocus();
         assertTrue(ironDropdown.opened);
 
         getList()[0].click();
         assertFalse(ironDropdown.opened);
 
-        clickDropdown();
+        clickDropdownFocus();
         assertTrue(ironDropdown.opened);
 
-        // Click outside dropdown to close the dropdown.
+        // Clicking outside the dropdown will cause it to lose focus and close.
+        // This will verify on-blur closes the dropdown.
         clickOutsideDropdown();
         assertFalse(ironDropdown.opened);
       });
 
-  test(assert(destination_dropdown_cros_test.TestNames.TabCloses), function() {
-    const destinationOne = createDestination('One', DestinationOrigin.CROS);
-    setItemList([destinationOne]);
-    dropdown.value = destinationOne;
-    const ironDropdown = dropdown.$$('iron-dropdown');
-
-    clickDropdown();
-    assertTrue(ironDropdown.opened);
-
-    tab();
-    assertFalse(ironDropdown.opened);
-  });
-
   test(
       assert(destination_dropdown_cros_test.TestNames.HighlightedAfterUpDown),
       function() {
diff --git a/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js b/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js
index 99a89f03..bc3c24b 100644
--- a/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js
+++ b/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js
@@ -181,3 +181,23 @@
       this.runMochaTest(
           scaling_settings_interactive_test.TestNames.AutoFocusInput);
     });
+
+GEN('#if defined(OS_CHROMEOS)');
+// eslint-disable-next-line no-var
+var PrintPreviewDestinationDropdownCrosTest =
+    class extends PrintPreviewInteractiveUITest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://print/test_loader.html?module=print_preview/destination_dropdown_cros_test.js';
+  }
+
+  /** @override */
+  get suiteName() {
+    return destination_dropdown_cros_test.suiteName;
+  }
+};
+
+TEST_F('PrintPreviewDestinationDropdownCrosTest', 'ClickCloses', function() {
+  this.runMochaTest(destination_dropdown_cros_test.TestNames.ClickCloses);
+});
+GEN('#endif');
diff --git a/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js b/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
index 703bcc3c5..32973c5 100644
--- a/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
+++ b/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
@@ -1142,14 +1142,6 @@
           destination_dropdown_cros_test.TestNames.CorrectListItems);
     });
 
-TEST_F('PrintPreviewDestinationDropdownCrosTest', 'ClickCloses', function() {
-  this.runMochaTest(destination_dropdown_cros_test.TestNames.ClickCloses);
-});
-
-TEST_F('PrintPreviewDestinationDropdownCrosTest', 'TabCloses', function() {
-  this.runMochaTest(destination_dropdown_cros_test.TestNames.TabCloses);
-});
-
 TEST_F(
     'PrintPreviewDestinationDropdownCrosTest', 'HighlightedAfterUpDown',
     function() {
diff --git a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
index 30c39f5..85c59a5 100644
--- a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
@@ -227,8 +227,8 @@
   }
 };
 
-// Flaky on Mac and Debug builds https://crbug.com/1090931
-GEN('#if defined(OS_MACOSX) || !defined(NDEBUG)');
+// Flaky on Debug builds https://crbug.com/1090931
+GEN('#if !defined(NDEBUG)');
 GEN('#define MAYBE_All DISABLED_All');
 GEN('#else');
 GEN('#define MAYBE_All All');
diff --git a/chrome/test/data/webui/settings/password_check_test.js b/chrome/test/data/webui/settings/password_check_test.js
index 8ea90796f..b4a7ca5 100644
--- a/chrome/test/data/webui/settings/password_check_test.js
+++ b/chrome/test/data/webui/settings/password_check_test.js
@@ -1039,7 +1039,16 @@
     const editDialog = createEditDialog(leakedPassword);
 
     assertEquals(leakedPassword.password, editDialog.$.passwordInput.value);
+
+    // Test that an empty password is considered invalid and disables the change
+    // button.
+    editDialog.$.passwordInput.value = '';
+    assertTrue(editDialog.$.passwordInput.invalid);
+    assertTrue(editDialog.$.save.disabled);
+
     editDialog.$.passwordInput.value = 'yadhtribym';
+    assertFalse(editDialog.$.passwordInput.invalid);
+    assertFalse(editDialog.$.save.disabled);
     editDialog.$.save.click();
 
     const interaction =
diff --git a/chrome/test/data/webui/settings/passwords_device_section_test.js b/chrome/test/data/webui/settings/passwords_device_section_test.js
index 85dac58e..c383576 100644
--- a/chrome/test/data/webui/settings/passwords_device_section_test.js
+++ b/chrome/test/data/webui/settings/passwords_device_section_test.js
@@ -74,11 +74,7 @@
 
     // The user only enters this page when they are eligible (signed-in but not
     // syncing) and opted-in to account storage.
-    syncBrowserProxy.storedAccounts = [{
-      fullName: 'john doe',
-      givenName: 'john',
-      email: 'john@gmail.com',
-    }];
+    syncBrowserProxy.storedAccounts = [{email: 'john@gmail.com'}];
     simulateStoredAccounts(syncBrowserProxy.storedAccounts);
     syncBrowserProxy.syncStatus = {signedIn: false};
     simulateSyncStatus(syncBrowserProxy.syncStatus);
diff --git a/chrome/test/data/webui/settings/passwords_section_test.js b/chrome/test/data/webui/settings/passwords_section_test.js
index a7742000..499dc8b 100644
--- a/chrome/test/data/webui/settings/passwords_section_test.js
+++ b/chrome/test/data/webui/settings/passwords_section_test.js
@@ -150,11 +150,7 @@
  */
 function simulateAccountStorageUser(passwordManager) {
   simulateSyncStatus({signedIn: false});
-  simulateStoredAccounts([{
-    fullName: 'john doe',
-    givenName: 'john',
-    email: 'john@gmail.com',
-  }]);
+  simulateStoredAccounts([{email: 'john@gmail.com'}]);
   passwordManager.setIsOptedInForAccountStorageAndNotify(true);
 
   flush();
@@ -1109,11 +1105,7 @@
           isDisplayed(passwordsSection.$.accountStorageButtonsContainer));
 
       // User signs in but is not opted in yet.
-      simulateStoredAccounts([{
-        fullName: 'john doe',
-        givenName: 'john',
-        email: 'john@gmail.com',
-      }]);
+      simulateStoredAccounts([{email: 'john@gmail.com'}]);
       passwordManager.setIsOptedInForAccountStorageAndNotify(false);
       flush();
       assertTrue(
@@ -1140,6 +1132,27 @@
           isDisplayed(passwordsSection.$.accountStorageButtonsContainer));
     });
 
+    // Test verifies the the account storage buttons are not shown for custom
+    // passphrase users.
+    test('accountStorageButonsNotShownForCustomPassphraseUser', function() {
+      loadTimeData.overrideValues({enableAccountStorage: true});
+
+      const passwordsSection =
+          elementFactory.createPasswordsSection(passwordManager, [], []);
+
+      simulateSyncStatus({signedIn: false});
+      simulateStoredAccounts([{email: 'john@gmail.com'}]);
+      // Simulate custom passphrase.
+      const syncPrefs = getSyncAllPrefs();
+      syncPrefs.encryptAllData = true;
+      webUIListenerCallback('sync-prefs-changed', syncPrefs);
+      flush();
+
+      assertTrue(
+          !passwordsSection.$.accountStorageButtonsContainer ||
+          passwordsSection.$.accountStorageButtonsContainer.hidden);
+    });
+
     // Test verifies that enabling sync hides the buttons for account storage
     // opt-in/out and the 'device passwords' page.
     test('enablingSyncHidesAccountStorageButtons', function() {
@@ -1172,11 +1185,7 @@
       const passwordsSection = elementFactory.createPasswordsSection(
           passwordManager, passwordList, []);
       simulateSyncStatus({signedIn: false});
-      simulateStoredAccounts([{
-        fullName: 'john doe',
-        givenName: 'john',
-        email: 'john@gmail.com',
-      }]);
+      simulateStoredAccounts([{email: 'john@gmail.com'}]);
       assertTrue(passwordsSection.$.devicePasswordsLink.hidden);
 
       // Opting in still doesn't display it because the user has no device
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index 80cb93eb..9c6d709 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -41,7 +41,6 @@
       "action_handler.h",
       "constants.cc",
       "constants.h",
-      "control_service.h",
       "crash_client.cc",
       "crash_client.h",
       "crash_reporter.cc",
@@ -90,8 +89,6 @@
       "app/app_wake.h",
       "configurator.cc",
       "configurator.h",
-      "control_service_in_process.cc",
-      "control_service_in_process.h",
       "dm_cached_policy_info.cc",
       "dm_cached_policy_info.h",
       "dm_message.cc",
@@ -111,6 +108,7 @@
       "prefs_impl.h",
       "tag.cc",
       "tag.h",
+      "update_apps.h",
       "update_service_in_process.cc",
       "update_service_in_process.h",
       "updater.cc",
@@ -131,8 +129,6 @@
         "external_constants_mac.mm",
         "installer_mac.cc",
         "lib_util_mac.mm",
-        "mac/control_service_out_of_process.h",
-        "mac/control_service_out_of_process.mm",
         "mac/update_service_out_of_process.h",
         "mac/update_service_out_of_process.mm",
         "prefs_mac.mm",
@@ -142,7 +138,6 @@
 
     if (is_win) {
       sources += [
-        "app/app_wake_win.cc",
         "app/server/win/com_classes.cc",
         "app/server/win/com_classes.h",
         "app/server/win/com_classes_legacy.cc",
diff --git a/chrome/updater/app/app_wake.cc b/chrome/updater/app/app_wake.cc
index 7f3fe3e..c6d17fe 100644
--- a/chrome/updater/app/app_wake.cc
+++ b/chrome/updater/app/app_wake.cc
@@ -4,20 +4,18 @@
 
 #include "chrome/updater/app/app_wake.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/logging.h"
-#include "build/build_config.h"
 #include "chrome/updater/app/app.h"
-#include "chrome/updater/control_service.h"
+#include "chrome/updater/configurator.h"
+#include "chrome/updater/prefs.h"
+#include "chrome/updater/update_apps.h"
+#include "chrome/updater/update_service.h"
 
 namespace updater {
 
-// TODO(sorin): Implement the control service for Windows. crbug.com/1105589.
-#if !defined(OS_WIN)
-
-// AppWake is a simple client which dials the same-versioned server via RPC and
-// tells that server to run its control tasks. This is done via the
-// ControlService interface.
 class AppWake : public App {
  public:
   AppWake() = default;
@@ -27,16 +25,37 @@
 
   // Overrides for App.
   void FirstTaskRun() override;
+  void Initialize() override;
+  void Uninitialize() override;
+
+  scoped_refptr<Configurator> config_;
+  scoped_refptr<UpdateService> update_service_;
 };
 
+void AppWake::Initialize() {
+  config_ = base::MakeRefCounted<Configurator>(CreateGlobalPrefs());
+}
+
+void AppWake::Uninitialize() {
+  update_service_->Uninitialize();
+}
+
+// AppWake triggers an update of all registered applications.
 void AppWake::FirstTaskRun() {
-  CreateControlService()->Run(base::BindOnce(&AppWake::Shutdown, this, 0));
+  update_service_ = CreateUpdateService(config_);
+  update_service_->UpdateAll(
+      base::BindRepeating([](UpdateService::UpdateState) {}),
+      base::BindOnce(
+          [](base::OnceCallback<void(int)> quit, UpdateService::Result result) {
+            const int exit_code = static_cast<int>(result);
+            VLOG(0) << "UpdateAll complete: exit_code = " << exit_code;
+            std::move(quit).Run(exit_code);
+          },
+          base::BindOnce(&AppWake::Shutdown, this)));
 }
 
 scoped_refptr<App> MakeAppWake() {
   return base::MakeRefCounted<AppWake>();
 }
 
-#endif
-
 }  // namespace updater
diff --git a/chrome/updater/app/app_wake_win.cc b/chrome/updater/app/app_wake_win.cc
deleted file mode 100644
index 542934a..0000000
--- a/chrome/updater/app/app_wake_win.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/updater/app/app_wake.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "chrome/updater/app/app.h"
-#include "chrome/updater/configurator.h"
-#include "chrome/updater/prefs.h"
-#include "chrome/updater/update_service.h"
-
-namespace updater {
-
-class AppWake : public App {
- public:
-  AppWake() = default;
-
- private:
-  ~AppWake() override = default;
-
-  // Overrides for App.
-  void FirstTaskRun() override;
-  void Initialize() override;
-  void Uninitialize() override;
-
-  scoped_refptr<Configurator> config_;
-  scoped_refptr<UpdateService> update_service_;
-};
-
-void AppWake::Initialize() {
-  config_ = base::MakeRefCounted<Configurator>(CreateGlobalPrefs());
-}
-
-void AppWake::Uninitialize() {
-  update_service_->Uninitialize();
-}
-
-// AppWake triggers an update of all registered applications.
-// TODO(sorin): Implement the control service for Windows. crbug.com/1105589.
-// This means that this code goes away, use the platform neutral implementation
-// of AppWake, which delegates to the control service.
-void AppWake::FirstTaskRun() {
-  update_service_ = CreateUpdateService(config_);
-  update_service_->UpdateAll(
-      base::BindRepeating([](UpdateService::UpdateState) {}),
-      base::BindOnce(
-          [](base::OnceCallback<void(int)> quit, UpdateService::Result result) {
-            const int exit_code = static_cast<int>(result);
-            VLOG(0) << "UpdateAll complete: exit_code = " << exit_code;
-            std::move(quit).Run(exit_code);
-          },
-          base::BindOnce(&AppWake::Shutdown, this)));
-}
-
-scoped_refptr<App> MakeAppWake() {
-  return base::MakeRefCounted<AppWake>();
-}
-
-}  // namespace updater
diff --git a/chrome/updater/app/server/mac/app_server.h b/chrome/updater/app/server/mac/app_server.h
index 90baa943..d0fa1447 100644
--- a/chrome/updater/app/server/mac/app_server.h
+++ b/chrome/updater/app/server/mac/app_server.h
@@ -49,11 +49,12 @@
 
   SEQUENCE_CHECKER(sequence_checker_);
 
-  base::scoped_nsobject<CRUUpdateCheckServiceXPCDelegate>
+  base::scoped_nsobject<CRUUpdateCheckXPCServiceDelegate>
       update_check_delegate_;
   base::scoped_nsobject<NSXPCListener> update_check_listener_;
-  base::scoped_nsobject<CRUControlServiceXPCDelegate> control_service_delegate_;
-  base::scoped_nsobject<NSXPCListener> control_service_listener_;
+  base::scoped_nsobject<CRUAdministrationXPCServiceDelegate>
+      administration_delegate_;
+  base::scoped_nsobject<NSXPCListener> administration_listener_;
 
   // Task runner bound to the main sequence and the update service instance.
   scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
diff --git a/chrome/updater/app/server/mac/server.mm b/chrome/updater/app/server/mac/server.mm
index d34c7aec..0998bda 100644
--- a/chrome/updater/app/server/mac/server.mm
+++ b/chrome/updater/app/server/mac/server.mm
@@ -19,7 +19,6 @@
 #import "chrome/updater/app/server/mac/app_server.h"
 #include "chrome/updater/app/server/mac/service_delegate.h"
 #include "chrome/updater/configurator.h"
-#include "chrome/updater/control_service_in_process.h"
 #include "chrome/updater/mac/setup/setup.h"
 #import "chrome/updater/mac/xpc_service_names.h"
 #include "chrome/updater/prefs.h"
@@ -35,7 +34,7 @@
   // These delegates need to have a reference to the AppServer. To break the
   // circular reference, we need to reset them.
   update_check_delegate_.reset();
-  control_service_delegate_.reset();
+  administration_delegate_.reset();
 
   AppServer::Uninitialize();
 }
@@ -50,7 +49,7 @@
   @autoreleasepool {
     // Sets up a listener and delegate for the CRUUpdateChecking XPC
     // connection
-    update_check_delegate_.reset([[CRUUpdateCheckServiceXPCDelegate alloc]
+    update_check_delegate_.reset([[CRUUpdateCheckXPCServiceDelegate alloc]
         initWithUpdateService:base::MakeRefCounted<UpdateServiceInProcess>(
                                   config_)
                     appServer:scoped_refptr<AppServerMac>(this)]);
@@ -61,17 +60,18 @@
 
     [update_check_listener_ resume];
 
-    // Sets up a listener and delegate for the CRUControlling XPC connection
-    control_service_delegate_.reset([[CRUControlServiceXPCDelegate alloc]
-        initWithControlService:base::MakeRefCounted<ControlServiceInProcess>()
-                     appServer:scoped_refptr<AppServerMac>(this)]);
+    // Sets up a listener and delegate for the CRUAdministering XPC connection
+    administration_delegate_.reset([[CRUAdministrationXPCServiceDelegate alloc]
+        initWithUpdateService:base::MakeRefCounted<UpdateServiceInProcess>(
+                                  config_)
+                    appServer:scoped_refptr<AppServerMac>(this)]);
 
-    control_service_listener_.reset([[NSXPCListener alloc]
+    administration_listener_.reset([[NSXPCListener alloc]
         initWithMachServiceName:base::mac::CFToNSCast(
-                                    CopyControlLaunchdName().get())]);
-    control_service_listener_.get().delegate = control_service_delegate_.get();
+                                    CopyAdministrationLaunchDName().get())]);
+    administration_listener_.get().delegate = administration_delegate_.get();
 
-    [control_service_listener_ resume];
+    [administration_listener_ resume];
   }
 }
 
diff --git a/chrome/updater/app/server/mac/service_delegate.h b/chrome/updater/app/server/mac/service_delegate.h
index f134037..a65f5b5 100644
--- a/chrome/updater/app/server/mac/service_delegate.h
+++ b/chrome/updater/app/server/mac/service_delegate.h
@@ -10,12 +10,11 @@
 #include "base/memory/scoped_refptr.h"
 
 namespace updater {
-class ControlService;
 class UpdateService;
 class AppServerMac;
 }
 
-@interface CRUUpdateCheckServiceXPCDelegate : NSObject <NSXPCListenerDelegate>
+@interface CRUUpdateCheckXPCServiceDelegate : NSObject <NSXPCListenerDelegate>
 
 - (instancetype)init NS_UNAVAILABLE;
 
@@ -27,14 +26,15 @@
 
 @end
 
-@interface CRUControlServiceXPCDelegate : NSObject <NSXPCListenerDelegate>
+@interface CRUAdministrationXPCServiceDelegate
+    : NSObject <NSXPCListenerDelegate>
 
 - (instancetype)init NS_UNAVAILABLE;
 
 // Designated initializer.
 - (instancetype)
-    initWithControlService:(scoped_refptr<updater::ControlService>)service
-                 appServer:(scoped_refptr<updater::AppServerMac>)appServer
+    initWithUpdateService:(scoped_refptr<updater::UpdateService>)service
+                appServer:(scoped_refptr<updater::AppServerMac>)appServer
     NS_DESIGNATED_INITIALIZER;
 
 @end
diff --git a/chrome/updater/app/server/mac/service_delegate.mm b/chrome/updater/app/server/mac/service_delegate.mm
index dc33469..72e1ea86 100644
--- a/chrome/updater/app/server/mac/service_delegate.mm
+++ b/chrome/updater/app/server/mac/service_delegate.mm
@@ -21,13 +21,13 @@
 #import "chrome/updater/app/server/mac/server.h"
 #import "chrome/updater/app/server/mac/service_protocol.h"
 #import "chrome/updater/app/server/mac/update_service_wrappers.h"
-#include "chrome/updater/control_service.h"
 #include "chrome/updater/mac/setup/setup.h"
 #import "chrome/updater/mac/xpc_service_names.h"
 #include "chrome/updater/update_service.h"
 #include "chrome/updater/updater_version.h"
 
-@interface CRUUpdateCheckServiceXPCImpl : NSObject <CRUUpdateChecking>
+@interface CRUUpdateCheckXPCServiceImpl
+    : NSObject <CRUUpdateChecking, CRUAdministering>
 
 - (instancetype)init NS_UNAVAILABLE;
 
@@ -39,12 +39,22 @@
                (scoped_refptr<base::SequencedTaskRunner>)callbackRunner
     NS_DESIGNATED_INITIALIZER;
 
+- (instancetype)
+       initWithUpdateService:(updater::UpdateService*)service
+                   appServer:(scoped_refptr<updater::AppServerMac>)appServer
+    updaterConnectionOptions:(NSXPCConnectionOptions)options
+              callbackRunner:
+                  (scoped_refptr<base::SequencedTaskRunner>)callbackRunner;
+
 @end
 
-@implementation CRUUpdateCheckServiceXPCImpl {
+@implementation CRUUpdateCheckXPCServiceImpl {
   updater::UpdateService* _service;
   scoped_refptr<updater::AppServerMac> _appServer;
   scoped_refptr<base::SequencedTaskRunner> _callbackRunner;
+  NSXPCConnectionOptions _updateCheckXPCConnectionOptions;
+  base::scoped_nsobject<NSXPCConnection> _updateCheckXPCConnection;
+  NSInteger _redialAttempts;
 }
 
 - (instancetype)
@@ -60,6 +70,38 @@
   return self;
 }
 
+- (instancetype)
+       initWithUpdateService:(updater::UpdateService*)service
+                   appServer:(scoped_refptr<updater::AppServerMac>)appServer
+    updaterConnectionOptions:(NSXPCConnectionOptions)options
+              callbackRunner:
+                  (scoped_refptr<base::SequencedTaskRunner>)callbackRunner {
+  [self initWithUpdateService:service
+                    appServer:appServer
+               callbackRunner:callbackRunner];
+  _updateCheckXPCConnectionOptions = options;
+  [self dialUpdateCheckXPCConnection];
+  return self;
+}
+
+- (void)dialUpdateCheckXPCConnection {
+  _updateCheckXPCConnection.reset([[NSXPCConnection alloc]
+      initWithMachServiceName:updater::GetServiceMachName().get()
+                      options:_updateCheckXPCConnectionOptions]);
+
+  _updateCheckXPCConnection.get().remoteObjectInterface =
+      updater::GetXPCUpdateCheckingInterface();
+
+  _updateCheckXPCConnection.get().interruptionHandler = ^{
+    LOG(WARNING) << "CRUUpdateCheckingService: XPC connection interrupted.";
+  };
+
+  _updateCheckXPCConnection.get().invalidationHandler = ^{
+    LOG(WARNING) << "CRUUpdateCheckingService: XPC connection invalidated.";
+  };
+  [_updateCheckXPCConnection resume];
+}
+
 #pragma mark CRUUpdateChecking
 - (void)checkForUpdatesWithUpdateState:(id<CRUUpdateStateObserving>)updateState
                                  reply:(void (^_Nonnull)(int rc))reply {
@@ -185,57 +227,14 @@
                                 request, std::move(cb)));
 }
 
-@end
+#pragma mark CRUAdministering
 
-@interface CRUControlServiceXPCImpl : NSObject <CRUControlling>
-
-- (instancetype)init NS_UNAVAILABLE;
-
-// Designated initializers.
-- (instancetype)
-    initWithControlService:(updater::ControlService*)service
-                 appServer:(scoped_refptr<updater::AppServerMac>)appServer
-            callbackRunner:
-                (scoped_refptr<base::SequencedTaskRunner>)callbackRunner
-    NS_DESIGNATED_INITIALIZER;
-
-@end
-
-@implementation CRUControlServiceXPCImpl {
-  updater::ControlService* _service;
-  scoped_refptr<updater::AppServerMac> _appServer;
-  scoped_refptr<base::SequencedTaskRunner> _callbackRunner;
-}
-
-- (instancetype)
-    initWithControlService:(updater::ControlService*)service
-                 appServer:(scoped_refptr<updater::AppServerMac>)appServer
-            callbackRunner:
-                (scoped_refptr<base::SequencedTaskRunner>)callbackRunner {
-  if (self = [super init]) {
-    _service = service;
-    _appServer = appServer;
-    _callbackRunner = callbackRunner;
-  }
-  return self;
-}
-
-#pragma mark CRUControlling
-- (void)performControlTasksWithReply:(void (^)(void))reply {
-  auto cb = base::BindOnce(base::RetainBlock(^(void) {
-    VLOG(0) << "performControlTasks complete.";
-    if (reply)
-      reply();
-  }));
-
-  _callbackRunner->PostTask(
-      FROM_HERE,
-      base::BindOnce(&updater::ControlService::Run, _service, std::move(cb)));
+- (void)performAdminTasks {
 }
 
 @end
 
-@implementation CRUUpdateCheckServiceXPCDelegate {
+@implementation CRUUpdateCheckXPCServiceDelegate {
   scoped_refptr<updater::UpdateService> _service;
   scoped_refptr<updater::AppServerMac> _appServer;
   scoped_refptr<base::SequencedTaskRunner> _callbackRunner;
@@ -259,8 +258,8 @@
 
   newConnection.exportedInterface = updater::GetXPCUpdateCheckingInterface();
 
-  base::scoped_nsobject<CRUUpdateCheckServiceXPCImpl> object(
-      [[CRUUpdateCheckServiceXPCImpl alloc]
+  base::scoped_nsobject<CRUUpdateCheckXPCServiceImpl> object(
+      [[CRUUpdateCheckXPCServiceImpl alloc]
           initWithUpdateService:_service.get()
                       appServer:_appServer
                  callbackRunner:_callbackRunner.get()]);
@@ -271,15 +270,15 @@
 
 @end
 
-@implementation CRUControlServiceXPCDelegate {
-  scoped_refptr<updater::ControlService> _service;
+@implementation CRUAdministrationXPCServiceDelegate {
+  scoped_refptr<updater::UpdateService> _service;
   scoped_refptr<updater::AppServerMac> _appServer;
   scoped_refptr<base::SequencedTaskRunner> _callbackRunner;
 }
 
 - (instancetype)
-    initWithControlService:(scoped_refptr<updater::ControlService>)service
-                 appServer:(scoped_refptr<updater::AppServerMac>)appServer {
+    initWithUpdateService:(scoped_refptr<updater::UpdateService>)service
+                appServer:(scoped_refptr<updater::AppServerMac>)appServer {
   if (self = [super init]) {
     _service = service;
     _callbackRunner = base::SequencedTaskRunnerHandle::Get();
@@ -292,13 +291,19 @@
   // Check to see if the other side of the connection is "okay";
   // if not, invalidate newConnection and return NO.
 
-  newConnection.exportedInterface = updater::GetXPCControllingInterface();
+  base::CommandLine* cmdLine = base::CommandLine::ForCurrentProcess();
+  NSXPCConnectionOptions options = cmdLine->HasSwitch(updater::kSystemSwitch)
+                                       ? NSXPCConnectionPrivileged
+                                       : 0;
 
-  base::scoped_nsobject<CRUControlServiceXPCImpl> object(
-      [[CRUControlServiceXPCImpl alloc]
-          initWithControlService:_service.get()
-                       appServer:_appServer
-                  callbackRunner:_callbackRunner.get()]);
+  newConnection.exportedInterface = updater::GetXPCAdministeringInterface();
+
+  base::scoped_nsobject<CRUUpdateCheckXPCServiceImpl> object(
+      [[CRUUpdateCheckXPCServiceImpl alloc]
+             initWithUpdateService:_service.get()
+                         appServer:_appServer
+          updaterConnectionOptions:options
+                    callbackRunner:_callbackRunner.get()]);
   newConnection.exportedObject = object.get();
   [newConnection resume];
   return YES;
diff --git a/chrome/updater/app/server/mac/service_protocol.h b/chrome/updater/app/server/mac/service_protocol.h
index c6007de..3f0c4520 100644
--- a/chrome/updater/app/server/mac/service_protocol.h
+++ b/chrome/updater/app/server/mac/service_protocol.h
@@ -47,12 +47,12 @@
 
 @end
 
-// Protocol for the XPC control tasks of the Updater.
-@protocol CRUControlling <NSObject>
+// Protocol for the XPC administration tasks of the Updater.
+@protocol CRUAdministering <NSObject>
 
-// Performs the control task (activate service, uninstall service, or no-op)
-// that is relevant to the state of the Updater.
-- (void)performControlTasksWithReply:(void (^_Nullable)(void))reply;
+// Performs the admin task (activate service, uninstall service, or no opp) that
+// is relevant to the state of the Updater.
+- (void)performAdminTasks;
 
 @end
 
@@ -62,9 +62,9 @@
 // CRUUpdateStateObserving protocols.
 NSXPCInterface* _Nonnull GetXPCUpdateCheckingInterface();
 
-// Constructs an NSXPCInterface for a connection using CRUControlling
+// Constructs an NSXPCInterface for a connection using CRUAdministering
 // protocol.
-NSXPCInterface* _Nonnull GetXPCControllingInterface();
+NSXPCInterface* _Nonnull GetXPCAdministeringInterface();
 
 }  // namespace updater
 
diff --git a/chrome/updater/app/server/mac/service_protocol.mm b/chrome/updater/app/server/mac/service_protocol.mm
index c0c6c9a..8cf57dc 100644
--- a/chrome/updater/app/server/mac/service_protocol.mm
+++ b/chrome/updater/app/server/mac/service_protocol.mm
@@ -30,8 +30,8 @@
   return updateCheckingInterface;
 }
 
-NSXPCInterface* GetXPCControllingInterface() {
-  return [NSXPCInterface interfaceWithProtocol:@protocol(CRUControlling)];
+NSXPCInterface* GetXPCAdministeringInterface() {
+  return [NSXPCInterface interfaceWithProtocol:@protocol(CRUAdministering)];
 }
 
 }  // namespace updater
diff --git a/chrome/updater/control_service.h b/chrome/updater/control_service.h
deleted file mode 100644
index df5cb2b..0000000
--- a/chrome/updater/control_service.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_UPDATER_CONTROL_SERVICE_H_
-#define CHROME_UPDATER_CONTROL_SERVICE_H_
-
-#include "base/callback_forward.h"
-#include "base/memory/ref_counted.h"
-
-namespace updater {
-
-// The ControlService is the cross-platform abstraction for performing admin
-// tasks on the updater.
-class ControlService : public base::RefCountedThreadSafe<ControlService> {
- public:
-  virtual void Run(base::OnceClosure callback) = 0;
-
-  // Provides a way to commit data or clean up resources before the task
-  // scheduler is shutting down.
-  virtual void Uninitialize() = 0;
-
- protected:
-  friend class base::RefCountedThreadSafe<ControlService>;
-
-  virtual ~ControlService() = default;
-};
-
-// A factory method to create a ControlService class instance.
-scoped_refptr<ControlService> CreateControlService();
-
-}  // namespace updater
-
-#endif  // CHROME_UPDATER_CONTROL_SERVICE_H_
diff --git a/chrome/updater/control_service_in_process.cc b/chrome/updater/control_service_in_process.cc
deleted file mode 100644
index d0dd10f..0000000
--- a/chrome/updater/control_service_in_process.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/updater/control_service_in_process.h"
-
-#include "base/callback.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-
-namespace updater {
-
-ControlServiceInProcess::ControlServiceInProcess()
-    : main_task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
-
-void ControlServiceInProcess::Run(base::OnceClosure callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  // TODO(crbug.com/1107586): Implement.
-}
-
-void ControlServiceInProcess::Uninitialize() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-ControlServiceInProcess::~ControlServiceInProcess() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-}  // namespace updater
diff --git a/chrome/updater/control_service_in_process.h b/chrome/updater/control_service_in_process.h
deleted file mode 100644
index 7e9bc2d..0000000
--- a/chrome/updater/control_service_in_process.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_UPDATER_CONTROL_SERVICE_IN_PROCESS_H_
-#define CHROME_UPDATER_CONTROL_SERVICE_IN_PROCESS_H_
-
-#include "base/callback_forward.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/sequence_checker.h"
-#include "chrome/updater/control_service.h"
-
-namespace base {
-class SequencedTaskRunner;
-}
-
-namespace updater {
-
-// All functions and callbacks must be called on the same sequence.
-class ControlServiceInProcess : public ControlService {
- public:
-  ControlServiceInProcess();
-
-  // Overrides for updater::ControlService.
-  void Run(base::OnceClosure callback) override;
-
-  void Uninitialize() override;
-
- private:
-  ~ControlServiceInProcess() override;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
-};
-
-}  // namespace updater
-
-#endif  // CHROME_UPDATER_CONTROL_SERVICE_IN_PROCESS_H_
diff --git a/chrome/updater/mac/control_service_out_of_process.h b/chrome/updater/mac/control_service_out_of_process.h
deleted file mode 100644
index d95d2c6..0000000
--- a/chrome/updater/mac/control_service_out_of_process.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_UPDATER_MAC_CONTROL_SERVICE_OUT_OF_PROCESS_H_
-#define CHROME_UPDATER_MAC_CONTROL_SERVICE_OUT_OF_PROCESS_H_
-
-#import <Foundation/Foundation.h>
-
-#include "base/callback_forward.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/sequence_checker.h"
-#include "chrome/updater/control_service.h"
-#include "chrome/updater/update_service.h"
-
-@class CRUControlServiceOutOfProcessImpl;
-
-namespace base {
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace updater {
-
-// All functions and callbacks must be called on the same sequence.
-class ControlServiceOutOfProcess : public ControlService {
- public:
-  explicit ControlServiceOutOfProcess(UpdateService::Scope scope);
-
-  // Overrides for ControlService.
-  void Run(base::OnceClosure callback) override;
-  void Uninitialize() override;
-
- private:
-  ~ControlServiceOutOfProcess() override;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  base::scoped_nsobject<CRUControlServiceOutOfProcessImpl> client_;
-  scoped_refptr<base::SequencedTaskRunner> callback_runner_;
-};
-
-}  // namespace updater
-
-#endif  // CHROME_UPDATER_MAC_CONTROL_SERVICE_OUT_OF_PROCESS_H_
diff --git a/chrome/updater/mac/control_service_out_of_process.mm b/chrome/updater/mac/control_service_out_of_process.mm
deleted file mode 100644
index 215bdee..0000000
--- a/chrome/updater/mac/control_service_out_of_process.mm
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/updater/mac/control_service_out_of_process.h"
-
-#import <Foundation/Foundation.h>
-
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#import "chrome/updater/app/server/mac/service_protocol.h"
-#import "chrome/updater/mac/xpc_service_names.h"
-#include "chrome/updater/update_service.h"
-
-// Interface to communicate with the XPC Control Service.
-@interface CRUControlServiceOutOfProcessImpl : NSObject <CRUControlling>
-
-- (instancetype)initPrivileged;
-
-@end
-
-@implementation CRUControlServiceOutOfProcessImpl {
-  base::scoped_nsobject<NSXPCConnection> _controlXPCConnection;
-}
-
-- (instancetype)init {
-  return [self initWithConnectionOptions:0];
-}
-
-- (instancetype)initPrivileged {
-  return [self initWithConnectionOptions:NSXPCConnectionPrivileged];
-}
-
-- (instancetype)initWithConnectionOptions:(NSXPCConnectionOptions)options {
-  if ((self = [super init])) {
-    _controlXPCConnection.reset([[NSXPCConnection alloc]
-        initWithMachServiceName:updater::GetVersionedServiceMachName().get()
-                        options:options]);
-
-    _controlXPCConnection.get().remoteObjectInterface =
-        updater::GetXPCControllingInterface();
-
-    _controlXPCConnection.get().interruptionHandler = ^{
-      LOG(WARNING) << "CRUControlling: XPC connection interrupted.";
-    };
-
-    _controlXPCConnection.get().invalidationHandler = ^{
-      LOG(WARNING) << "CRUControlling: XPC connection invalidated.";
-    };
-
-    [_controlXPCConnection resume];
-  }
-
-  return self;
-}
-
-- (void)dealloc {
-  [_controlXPCConnection invalidate];
-  [super dealloc];
-}
-
-- (void)performControlTasksWithReply:(void (^)(void))reply {
-  auto errorHandler = ^(NSError* xpcError) {
-    LOG(ERROR) << "XPC connection failed: "
-               << base::SysNSStringToUTF8([xpcError description]);
-    reply();
-  };
-
-  [[_controlXPCConnection remoteObjectProxyWithErrorHandler:errorHandler]
-      performControlTasksWithReply:reply];
-}
-
-@end
-
-namespace updater {
-
-ControlServiceOutOfProcess::ControlServiceOutOfProcess(
-    UpdateService::Scope scope)
-    : callback_runner_(base::SequencedTaskRunnerHandle::Get()) {
-  switch (scope) {
-    case UpdateService::Scope::kSystem:
-      client_.reset([[CRUControlServiceOutOfProcessImpl alloc] initPrivileged]);
-      break;
-    case UpdateService::Scope::kUser:
-      client_.reset([[CRUControlServiceOutOfProcessImpl alloc] init]);
-      break;
-  }
-}
-
-void ControlServiceOutOfProcess::Run(base::OnceClosure callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  __block base::OnceClosure block_callback = std::move(callback);
-  auto reply = ^() {
-    callback_runner_->PostTask(FROM_HERE,
-                               base::BindOnce(std::move(block_callback)));
-  };
-
-  [client_ performControlTasksWithReply:reply];
-}
-
-void ControlServiceOutOfProcess::Uninitialize() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-ControlServiceOutOfProcess::~ControlServiceOutOfProcess() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-}  // namespace updater
diff --git a/chrome/updater/mac/setup/setup.h b/chrome/updater/mac/setup/setup.h
index 297d9d6..4bfd8dad 100644
--- a/chrome/updater/mac/setup/setup.h
+++ b/chrome/updater/mac/setup/setup.h
@@ -24,11 +24,8 @@
 // Failed to remove versioned update service job from Launchd.
 constexpr int kFailedToRemoveCandidateUpdateServiceJobFromLaunchd = 21;
 
-// Failed to remove versioned control job from Launchd.
-constexpr int kFailedToRemoveControlJobFromLaunchd = 22;
-
-// Failed to remove versioned wake job from Launchd.
-constexpr int kFailedToRemoveWakeJobFromLaunchd = 23;
+// Failed to remove versioned administration job from Launchd.
+constexpr int kFailedToRemoveAdministrationJobFromLaunchd = 22;
 
 // Failed to create the active(unversioned) update service Launchd plist.
 constexpr int kFailedToCreateUpdateServiceLaunchdJobPlist = 30;
@@ -36,11 +33,8 @@
 // Failed to create the versioned update service Launchd plist.
 constexpr int kFailedToCreateVersionedUpdateServiceLaunchdJobPlist = 31;
 
-// Failed to create the versioned control Launchd plist.
-constexpr int kFailedToCreateControlLaunchdJobPlist = 32;
-
-// Failed to create the versioned wake Launchd plist.
-constexpr int kFailedToCreateWakeLaunchdJobPlist = 33;
+// Failed to create the versioned administration Launchd plist.
+constexpr int kFailedToCreateAdministrationLaunchdJobPlist = 32;
 
 // Failed to start the active(unversioned) update service job.
 constexpr int kFailedToStartLaunchdActiveServiceJob = 40;
@@ -48,11 +42,8 @@
 // Failed to start the versioned update service job.
 constexpr int kFailedToStartLaunchdVersionedServiceJob = 41;
 
-// Failed to start the control job.
-constexpr int kFailedToStartLaunchdControlJob = 42;
-
-// Failed to start the wake job.
-constexpr int kFailedToStartLaunchdWakeJob = 43;
+// Failed to start the administration job.
+constexpr int kFailedToStartLaunchdAdministrationJob = 42;
 
 }  // namespace setup_exit_codes
 
diff --git a/chrome/updater/mac/setup/setup.mm b/chrome/updater/mac/setup/setup.mm
index 6c7e188..15aa171 100644
--- a/chrome/updater/mac/setup/setup.mm
+++ b/chrome/updater/mac/setup/setup.mm
@@ -114,15 +114,17 @@
 }
 
 base::ScopedCFTypeRef<CFDictionaryRef> CreateServiceLaunchdPlist(
+    const base::ScopedCFTypeRef<CFStringRef> label,
     const base::FilePath& updater_path) {
   // See the man page for launchd.plist.
   NSDictionary<NSString*, id>* launchd_plist = @{
-    @LAUNCH_JOBKEY_LABEL : GetServiceLaunchdLabel(),
+    @LAUNCH_JOBKEY_LABEL : base::mac::CFToNSCast(label),
     @LAUNCH_JOBKEY_PROGRAMARGUMENTS : @[
       base::SysUTF8ToNSString(updater_path.value()),
       MakeProgramArgument(kServerSwitch)
     ],
-    @LAUNCH_JOBKEY_MACHSERVICES : @{GetServiceMachName() : @YES},
+    @LAUNCH_JOBKEY_MACHSERVICES :
+        @{GetServiceMachName(base::mac::CFToNSCast(label)) : @YES},
     @LAUNCH_JOBKEY_ABANDONPROCESSGROUP : @NO,
     @LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE : @"Aqua"
   };
@@ -132,7 +134,7 @@
       base::scoped_policy::RETAIN);
 }
 
-base::ScopedCFTypeRef<CFDictionaryRef> CreateWakeLaunchdPlist(
+base::ScopedCFTypeRef<CFDictionaryRef> CreateAdministrationLaunchdPlist(
     const base::FilePath& updater_path) {
   // See the man page for launchd.plist.
   NSMutableArray<NSString*>* program_arguments =
@@ -145,7 +147,8 @@
     [program_arguments addObject:MakeProgramArgument(kSystemSwitch)];
 
   NSDictionary<NSString*, id>* launchd_plist = @{
-    @LAUNCH_JOBKEY_LABEL : GetWakeLaunchdLabel(),
+    @LAUNCH_JOBKEY_LABEL :
+        base::mac::CFToNSCast(CopyAdministrationLaunchDName()),
     @LAUNCH_JOBKEY_PROGRAMARGUMENTS : program_arguments,
     @LAUNCH_JOBKEY_STARTINTERVAL : @3600,
     @LAUNCH_JOBKEY_ABANDONPROCESSGROUP : @NO,
@@ -157,56 +160,28 @@
       base::scoped_policy::RETAIN);
 }
 
-base::ScopedCFTypeRef<CFDictionaryRef> CreateControlLaunchdPlist(
+bool CreateUpdateServiceLaunchdJobPlist(
+    const base::ScopedCFTypeRef<CFStringRef> name,
     const base::FilePath& updater_path) {
-  // See the man page for launchd.plist.
-  NSDictionary<NSString*, id>* launchd_plist = @{
-    @LAUNCH_JOBKEY_LABEL : GetControlLaunchdLabel(),
-    @LAUNCH_JOBKEY_PROGRAMARGUMENTS : @[
-      base::SysUTF8ToNSString(updater_path.value()),
-      MakeProgramArgument(kServerSwitch)
-    ],
-    @LAUNCH_JOBKEY_MACHSERVICES : @{GetVersionedServiceMachName() : @YES},
-    @LAUNCH_JOBKEY_ABANDONPROCESSGROUP : @NO,
-    @LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE : @"Aqua"
-  };
-
-  return base::ScopedCFTypeRef<CFDictionaryRef>(
-      base::mac::CFCast<CFDictionaryRef>(launchd_plist),
-      base::scoped_policy::RETAIN);
-}
-
-bool CreateUpdateServiceLaunchdJobPlist(const base::FilePath& updater_path) {
   // We're creating directories and writing a file.
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                 base::BlockingType::MAY_BLOCK);
 
   base::ScopedCFTypeRef<CFDictionaryRef> plist(
-      CreateServiceLaunchdPlist(updater_path));
+      CreateServiceLaunchdPlist(name, updater_path));
   return Launchd::GetInstance()->WritePlistToFile(
-      LaunchdDomain(), ServiceLaunchdType(), CopyServiceLaunchdName().release(),
-      plist);
+      LaunchdDomain(), ServiceLaunchdType(), name, plist);
 }
 
-bool CreateWakeLaunchdJobPlist(const base::FilePath& updater_path) {
+bool CreateUpdateAdministrationLaunchdJobPlist(
+    const base::FilePath& updater_path) {
   // We're creating directories and writing a file.
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                 base::BlockingType::MAY_BLOCK);
   base::ScopedCFTypeRef<CFDictionaryRef> plist(
-      CreateWakeLaunchdPlist(updater_path));
+      CreateAdministrationLaunchdPlist(updater_path));
   return Launchd::GetInstance()->WritePlistToFile(
-      LaunchdDomain(), ServiceLaunchdType(), CopyWakeLaunchdName().release(),
-      plist);
-}
-
-bool CreateControlLaunchdJobPlist(const base::FilePath& updater_path) {
-  // We're creating directories and writing a file.
-  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
-                                                base::BlockingType::MAY_BLOCK);
-  base::ScopedCFTypeRef<CFDictionaryRef> plist(
-      CreateControlLaunchdPlist(updater_path));
-  return Launchd::GetInstance()->WritePlistToFile(
-      LaunchdDomain(), ServiceLaunchdType(), CopyControlLaunchdName().release(),
+      LaunchdDomain(), ServiceLaunchdType(), CopyAdministrationLaunchDName(),
       plist);
 }
 
@@ -216,20 +191,14 @@
       LaunchdDomain(), ServiceLaunchdType(), name, CFSTR("Aqua"));
 }
 
-bool StartUpdateWakeVersionedLaunchdJob() {
+bool StartUpdateAdministrationVersionedLaunchdJob() {
   return Launchd::GetInstance()->RestartJob(
-      LaunchdDomain(), ServiceLaunchdType(), CopyWakeLaunchdName().release(),
-      CFSTR("Aqua"));
-}
-
-bool StartUpdateControlVersionedLaunchdJob() {
-  return Launchd::GetInstance()->RestartJob(
-      LaunchdDomain(), ServiceLaunchdType(), CopyControlLaunchdName().release(),
+      LaunchdDomain(), ServiceLaunchdType(), CopyAdministrationLaunchDName(),
       CFSTR("Aqua"));
 }
 
 bool StartLaunchdServiceJob() {
-  return StartUpdateServiceVersionedLaunchdJob(CopyServiceLaunchdName());
+  return StartUpdateServiceVersionedLaunchdJob(CopyServiceLaunchDName());
 }
 
 bool RemoveJobFromLaunchd(Launchd::Domain domain,
@@ -256,15 +225,11 @@
 }
 
 bool RemoveUpdateServiceJobFromLaunchd() {
-  return RemoveUpdateServiceJobFromLaunchd(CopyServiceLaunchdName());
+  return RemoveUpdateServiceJobFromLaunchd(CopyServiceLaunchDName());
 }
 
-bool RemoveUpdateWakeJobFromLaunchd() {
-  return RemoveClientJobFromLaunchd(CopyWakeLaunchdName());
-}
-
-bool RemoveUpdateControlJobFromLaunchd() {
-  return RemoveClientJobFromLaunchd(CopyControlLaunchdName());
+bool RemoveUpdateAdministrationJobFromLaunchd() {
+  return RemoveClientJobFromLaunchd(CopyAdministrationLaunchDName());
 }
 
 bool DeleteInstallFolder(const base::FilePath& installed_path) {
@@ -291,24 +256,20 @@
       dest_path.Append(GetUpdaterAppName())
           .Append(GetUpdaterAppExecutablePath());
 
-  if (!CreateWakeLaunchdJobPlist(updater_executable_path))
-    return setup_exit_codes::kFailedToCreateWakeLaunchdJobPlist;
+  if (!CreateUpdateAdministrationLaunchdJobPlist(
+          updater_executable_path)) {
+    return setup_exit_codes::kFailedToCreateAdministrationLaunchdJobPlist;
+  }
 
-  if (!CreateControlLaunchdJobPlist(updater_executable_path))
-    return setup_exit_codes::kFailedToCreateControlLaunchdJobPlist;
-
-  if (!StartUpdateControlVersionedLaunchdJob())
-    return setup_exit_codes::kFailedToStartLaunchdControlJob;
-
-  if (!StartUpdateWakeVersionedLaunchdJob())
-    return setup_exit_codes::kFailedToStartLaunchdWakeJob;
+  if (!StartUpdateAdministrationVersionedLaunchdJob()) {
+    return setup_exit_codes::kFailedToStartLaunchdAdministrationJob;
+  }
 
   return setup_exit_codes::kSuccess;
 }
 
 int UninstallCandidate() {
-  RemoveUpdateControlJobFromLaunchd();
-  RemoveUpdateWakeJobFromLaunchd();
+  RemoveUpdateAdministrationJobFromLaunchd();
   DeleteInstallFolder(GetVersionedUpdaterFolderPath());
   return setup_exit_codes::kSuccess;
 }
@@ -319,11 +280,14 @@
       dest_path.Append(GetUpdaterAppName())
           .Append(GetUpdaterAppExecutablePath());
 
-  if (!CreateUpdateServiceLaunchdJobPlist(updater_executable_path))
+  if (!CreateUpdateServiceLaunchdJobPlist(CopyServiceLaunchDName(),
+                                          updater_executable_path)) {
     return setup_exit_codes::kFailedToCreateUpdateServiceLaunchdJobPlist;
+  }
 
-  if (!StartLaunchdServiceJob())
+  if (!StartLaunchdServiceJob()) {
     return setup_exit_codes::kFailedToStartLaunchdActiveServiceJob;
+  }
 
   return setup_exit_codes::kSuccess;
 }
diff --git a/chrome/updater/mac/update_service_out_of_process.mm b/chrome/updater/mac/update_service_out_of_process.mm
index f791ddd..4c5e133 100644
--- a/chrome/updater/mac/update_service_out_of_process.mm
+++ b/chrome/updater/mac/update_service_out_of_process.mm
@@ -128,6 +128,68 @@
 
 @end
 
+// Interface to communicate with the XPC Updater Service.
+@interface CRUAdministrationServiceOutOfProcessImpl
+    : NSObject <CRUAdministering>
+
+- (instancetype)initPrivileged;
+
+@end
+
+@implementation CRUAdministrationServiceOutOfProcessImpl {
+  base::scoped_nsobject<NSXPCConnection> _administrationXPCConnection;
+}
+
+- (instancetype)init {
+  return [self initWithConnectionOptions:0];
+}
+
+- (instancetype)initPrivileged {
+  return [self initWithConnectionOptions:NSXPCConnectionPrivileged];
+}
+
+- (instancetype)initWithConnectionOptions:(NSXPCConnectionOptions)options {
+  if ((self = [super init])) {
+    _administrationXPCConnection.reset([[NSXPCConnection alloc]
+        initWithMachServiceName:base::mac::CFToNSCast(
+                                    updater::CopyAdministrationLaunchDName()
+                                        .get())
+                        options:options]);
+
+    _administrationXPCConnection.get().remoteObjectInterface =
+        updater::GetXPCAdministeringInterface();
+
+    _administrationXPCConnection.get().interruptionHandler = ^{
+      LOG(WARNING) << "CRUAdministering: XPC connection interrupted.";
+    };
+
+    _administrationXPCConnection.get().invalidationHandler = ^{
+      LOG(WARNING) << "CRUAdministering: XPC connection invalidated.";
+    };
+
+    [_administrationXPCConnection resume];
+  }
+
+  return self;
+}
+
+- (void)dealloc {
+  [_administrationXPCConnection invalidate];
+  [super dealloc];
+}
+
+- (void)performAdminTasks {
+  auto errorHandler = ^(NSError* xpcError) {
+    LOG(ERROR) << "XPC connection failed: "
+               << base::SysNSStringToUTF8([xpcError description]);
+  };
+
+  [[_administrationXPCConnection remoteObjectProxyWithErrorHandler:errorHandler]
+      performAdminTasks];
+}
+
+@end
+
 namespace updater {
 
 UpdateServiceOutOfProcess::UpdateServiceOutOfProcess(
@@ -139,6 +201,8 @@
     case UpdateService::Scope::kUser:
       client_.reset([[CRUUpdateServiceOutOfProcessImpl alloc] init]);
       break;
+    default:
+      CHECK(false) << "Unexpected value for UpdateService::Scope";
   }
   callback_runner_ = base::SequencedTaskRunnerHandle::Get();
 }
diff --git a/chrome/updater/mac/xpc_service_names.h b/chrome/updater/mac/xpc_service_names.h
index 6611ba8..06eb23e 100644
--- a/chrome/updater/mac/xpc_service_names.h
+++ b/chrome/updater/mac/xpc_service_names.h
@@ -10,14 +10,12 @@
 
 namespace updater {
 
-base::ScopedCFTypeRef<CFStringRef> CopyServiceLaunchdName();
-base::ScopedCFTypeRef<CFStringRef> CopyWakeLaunchdName();
-base::ScopedCFTypeRef<CFStringRef> CopyControlLaunchdName();
-base::scoped_nsobject<NSString> GetServiceLaunchdLabel();
-base::scoped_nsobject<NSString> GetWakeLaunchdLabel();
-base::scoped_nsobject<NSString> GetControlLaunchdLabel();
+base::ScopedCFTypeRef<CFStringRef> CopyServiceLaunchDName();
+base::ScopedCFTypeRef<CFStringRef> CopyAdministrationLaunchDName();
+base::scoped_nsobject<NSString> GetServiceLaunchDLabel();
+base::scoped_nsobject<NSString> GetAdministrationLaunchDLabel();
+base::scoped_nsobject<NSString> GetServiceMachName(NSString* name);
 base::scoped_nsobject<NSString> GetServiceMachName();
-base::scoped_nsobject<NSString> GetVersionedServiceMachName();
 
 }  // namespace updater
 
diff --git a/chrome/updater/mac/xpc_service_names.mm b/chrome/updater/mac/xpc_service_names.mm
index fc5ee379..fa464161 100644
--- a/chrome/updater/mac/xpc_service_names.mm
+++ b/chrome/updater/mac/xpc_service_names.mm
@@ -12,33 +12,23 @@
 
 namespace updater {
 
-base::ScopedCFTypeRef<CFStringRef> CopyServiceLaunchdName() {
+base::ScopedCFTypeRef<CFStringRef> CopyServiceLaunchDName() {
   return base::SysUTF8ToCFStringRef(MAC_BUNDLE_IDENTIFIER_STRING ".service");
 }
 
-base::ScopedCFTypeRef<CFStringRef> CopyWakeLaunchdName() {
+base::ScopedCFTypeRef<CFStringRef> CopyAdministrationLaunchDName() {
   return base::SysUTF8ToCFStringRef(MAC_BUNDLE_IDENTIFIER_STRING
-                                    ".wake." UPDATER_VERSION_STRING);
+                                    ".admin." UPDATER_VERSION_STRING);
 }
 
-base::ScopedCFTypeRef<CFStringRef> CopyControlLaunchdName() {
-  return base::SysUTF8ToCFStringRef(MAC_BUNDLE_IDENTIFIER_STRING
-                                    ".control." UPDATER_VERSION_STRING);
-}
-
-base::scoped_nsobject<NSString> GetServiceLaunchdLabel() {
+base::scoped_nsobject<NSString> GetServiceLaunchDLabel() {
   return base::scoped_nsobject<NSString>(
-      base::mac::CFToNSCast(CopyServiceLaunchdName().release()));
+      base::mac::CFToNSCast(CopyServiceLaunchDName().release()));
 }
 
-base::scoped_nsobject<NSString> GetWakeLaunchdLabel() {
+base::scoped_nsobject<NSString> GetAdministrationLaunchDLabel() {
   return base::scoped_nsobject<NSString>(
-      base::mac::CFToNSCast(CopyWakeLaunchdName().release()));
-}
-
-base::scoped_nsobject<NSString> GetControlLaunchdLabel() {
-  return base::scoped_nsobject<NSString>(
-      base::mac::CFToNSCast(CopyControlLaunchdName().release()));
+      base::mac::CFToNSCast(CopyAdministrationLaunchDName().release()));
 }
 
 base::scoped_nsobject<NSString> GetServiceMachName(NSString* name) {
@@ -49,17 +39,10 @@
 
 base::scoped_nsobject<NSString> GetServiceMachName() {
   base::scoped_nsobject<NSString> name(
-      base::mac::CFToNSCast(CopyServiceLaunchdName().release()));
-  return GetServiceMachName(name);
-}
-
-base::scoped_nsobject<NSString> GetVersionedServiceMachName() {
-  base::scoped_nsobject<NSString> name([NSString
-      stringWithFormat:@"%@.%@",
-                       base::mac::CFToNSCast(
-                           CopyServiceLaunchdName().release()),
-                       base::SysUTF8ToNSString(UPDATER_VERSION_STRING)]);
-  return GetServiceMachName(name);
+      base::mac::CFToNSCast(CopyServiceLaunchDName().release()));
+  return base::scoped_nsobject<NSString>(
+      [name stringByAppendingFormat:@".%lu", [GetServiceLaunchDLabel() hash]],
+      base::scoped_policy::RETAIN);
 }
 
 }  // namespace updater
diff --git a/chrome/updater/test/integration_tests_mac.mm b/chrome/updater/test/integration_tests_mac.mm
index 0828279..3d83e6ce 100644
--- a/chrome/updater/test/integration_tests_mac.mm
+++ b/chrome/updater/test/integration_tests_mac.mm
@@ -53,31 +53,25 @@
 void Clean() {
   EXPECT_TRUE(base::DeletePathRecursively(GetProductPath()));
   EXPECT_TRUE(Launchd::GetInstance()->DeletePlist(
-      Launchd::User, Launchd::Agent, updater::CopyWakeLaunchdName()));
+      Launchd::User, Launchd::Agent, updater::CopyAdministrationLaunchDName()));
   EXPECT_TRUE(Launchd::GetInstance()->DeletePlist(
-      Launchd::User, Launchd::Agent, updater::CopyControlLaunchdName()));
-  EXPECT_TRUE(Launchd::GetInstance()->DeletePlist(
-      Launchd::User, Launchd::Agent, updater::CopyServiceLaunchdName()));
+      Launchd::User, Launchd::Agent, updater::CopyServiceLaunchDName()));
 }
 
 void ExpectClean() {
   // Files must not exist on the file system.
   EXPECT_FALSE(base::PathExists(GetProductPath()));
   EXPECT_FALSE(Launchd::GetInstance()->PlistExists(
-      Launchd::User, Launchd::Agent, updater::CopyWakeLaunchdName()));
+      Launchd::User, Launchd::Agent, updater::CopyAdministrationLaunchDName()));
   EXPECT_FALSE(Launchd::GetInstance()->PlistExists(
-      Launchd::User, Launchd::Agent, updater::CopyControlLaunchdName()));
-  EXPECT_FALSE(Launchd::GetInstance()->PlistExists(
-      Launchd::User, Launchd::Agent, updater::CopyServiceLaunchdName()));
+      Launchd::User, Launchd::Agent, updater::CopyServiceLaunchDName()));
 }
 
 void ExpectInstalled() {
   // Files must exist on the file system.
   EXPECT_TRUE(base::PathExists(GetProductPath()));
-  EXPECT_TRUE(Launchd::GetInstance()->PlistExists(Launchd::User, Launchd::Agent,
-                                                  CopyWakeLaunchdName()));
-  EXPECT_TRUE(Launchd::GetInstance()->PlistExists(Launchd::User, Launchd::Agent,
-                                                  CopyControlLaunchdName()));
+  EXPECT_TRUE(Launchd::GetInstance()->PlistExists(
+      Launchd::User, Launchd::Agent, CopyAdministrationLaunchDName()));
 }
 
 void Install() {
@@ -94,7 +88,7 @@
   // Files must exist on the file system.
   EXPECT_TRUE(base::PathExists(GetProductPath()));
   EXPECT_TRUE(Launchd::GetInstance()->PlistExists(Launchd::User, Launchd::Agent,
-                                                  CopyServiceLaunchdName()));
+                                                  CopyServiceLaunchDName()));
 }
 
 void PromoteCandidate() {
diff --git a/chrome/updater/update_apps.h b/chrome/updater/update_apps.h
new file mode 100644
index 0000000..79cb6de
--- /dev/null
+++ b/chrome/updater/update_apps.h
@@ -0,0 +1,24 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_UPDATE_APPS_H_
+#define CHROME_UPDATER_UPDATE_APPS_H_
+
+#include "base/memory/scoped_refptr.h"
+
+namespace update_client {
+class Configurator;
+}  // namespace update_client
+
+namespace updater {
+
+class UpdateService;
+
+// A factory method to create an UpdateService class instance.
+scoped_refptr<UpdateService> CreateUpdateService(
+    scoped_refptr<update_client::Configurator> config);
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_UPDATE_APPS_H_
diff --git a/chrome/updater/update_apps_mac.mm b/chrome/updater/update_apps_mac.mm
index 75e23de..5868121b 100644
--- a/chrome/updater/update_apps_mac.mm
+++ b/chrome/updater/update_apps_mac.mm
@@ -2,11 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/updater/update_apps.h"
+
 #include "base/command_line.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/updater/configurator.h"
 #include "chrome/updater/constants.h"
-#include "chrome/updater/mac/control_service_out_of_process.h"
 #include "chrome/updater/mac/update_service_out_of_process.h"
 #include "chrome/updater/update_service_in_process.h"
 
@@ -25,13 +26,4 @@
                    UpdateService::Scope::kUser);
 }
 
-scoped_refptr<ControlService> CreateControlService() {
-  base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
-  return cmdline->HasSwitch(kSystemSwitch)
-             ? base::MakeRefCounted<ControlServiceOutOfProcess>(
-                   UpdateService::Scope::kSystem)
-             : base::MakeRefCounted<ControlServiceOutOfProcess>(
-                   UpdateService::Scope::kUser);
-}
-
 }  // namespace updater
diff --git a/chrome/updater/update_apps_win.cc b/chrome/updater/update_apps_win.cc
index 4b96538..36f43ef 100644
--- a/chrome/updater/update_apps_win.cc
+++ b/chrome/updater/update_apps_win.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/updater/update_apps.h"
+
 #include "base/command_line.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/updater/configurator.h"
diff --git a/chrome/updater/update_service.h b/chrome/updater/update_service.h
index 17dd7f2..c34e914e 100644
--- a/chrome/updater/update_service.h
+++ b/chrome/updater/update_service.h
@@ -11,10 +11,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/version.h"
 
-namespace update_client {
-class Configurator;
-}  // namespace update_client
-
 namespace updater {
 
 struct RegistrationRequest;
@@ -200,10 +196,6 @@
   virtual ~UpdateService() = default;
 };
 
-// A factory method to create an UpdateService class instance.
-scoped_refptr<UpdateService> CreateUpdateService(
-    scoped_refptr<update_client::Configurator> config);
-
 }  // namespace updater
 
 #endif  // CHROME_UPDATER_UPDATE_SERVICE_H_
diff --git a/chrome/updater/win/app_install.cc b/chrome/updater/win/app_install.cc
index a15c6922..e19b4a8d 100644
--- a/chrome/updater/win/app_install.cc
+++ b/chrome/updater/win/app_install.cc
@@ -62,6 +62,14 @@
 
 class AppInstallController;
 
+scoped_refptr<UpdateService> CreateUpdateService(
+    scoped_refptr<update_client::Configurator> config) {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSingleProcessSwitch))
+    return base::MakeRefCounted<UpdateServiceInProcess>(config);
+  else
+    return base::MakeRefCounted<UpdateServiceOutOfProcess>();
+}
+
 // Implements a simple inter-thread communication protocol based on Windows
 // messages exchanged between the application installer and its UI.
 //
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastCommandLineHelper.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastCommandLineHelper.java
index ea3a3b8..9805c0d 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastCommandLineHelper.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastCommandLineHelper.java
@@ -66,6 +66,7 @@
      * Reads command line args from persistent storage and initializes the CommandLine with those
      * args. Does not initialize CommandLine if it has been already been done.
      */
+    @SuppressWarnings("VisibleForTests")  // For call to cmdline.hasSwitch()
     public static void initCommandLineWithSavedArgs(CommandLineInitializer commandLineInitializer) {
         // CommandLine is a singleton, so check whether CastCommandLineHelper has initialized it
         // already and do nothing if so. We keep track of this in a static variable so we can still
diff --git a/chromeos/components/account_manager/account_manager.cc b/chromeos/components/account_manager/account_manager.cc
index 3d8af0e..6beaf610 100644
--- a/chromeos/components/account_manager/account_manager.cc
+++ b/chromeos/components/account_manager/account_manager.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/callback_forward.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/important_file_writer.h"
@@ -168,6 +169,16 @@
   pref_service_ = pref_service;
 }
 
+void AccountManager::InitializeInEphemeralMode(
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
+  Initialize(/* home_dir= */ base::FilePath(), url_loader_factory,
+             /* delay_network_call_runner= */
+             base::BindRepeating(
+                 [](base::OnceClosure closure) { std::move(closure).Run(); }),
+             /* task_runner= */ nullptr, /* initialization_callback= */
+             base::DoNothing());
+}
+
 void AccountManager::Initialize(
     const base::FilePath& home_dir,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
@@ -215,19 +226,28 @@
   task_runner_ = task_runner;
 
   base::FilePath tokens_file_path;
-  if (!home_dir_.empty()) {
+  if (!IsEphemeralMode()) {
+    DCHECK(task_runner_);
     tokens_file_path = home_dir_.Append(kTokensFileName);
     writer_ = std::make_unique<base::ImportantFileWriter>(tokens_file_path,
                                                           task_runner_);
   }
   initialization_callbacks_.emplace_back(std::move(initialization_callback));
 
-  PostTaskAndReplyWithResult(
-      task_runner_.get(), FROM_HERE,
-      base::BindOnce(&AccountManager::LoadAccountsFromDisk, tokens_file_path),
-      base::BindOnce(
-          &AccountManager::InsertAccountsAndRunInitializationCallbacks,
-          weak_factory_.GetWeakPtr(), initialization_start_time));
+  if (!IsEphemeralMode()) {
+    DCHECK(task_runner_);
+    PostTaskAndReplyWithResult(
+        task_runner_.get(), FROM_HERE,
+        base::BindOnce(&AccountManager::LoadAccountsFromDisk, tokens_file_path),
+        base::BindOnce(
+            &AccountManager::InsertAccountsAndRunInitializationCallbacks,
+            weak_factory_.GetWeakPtr(), initialization_start_time));
+  } else {
+    // We are running in ephemeral mode. There is nothing to load from disk.
+    RecordTokenLoadStatus(TokenLoadStatus::kSuccess);
+    InsertAccountsAndRunInitializationCallbacks(initialization_start_time,
+                                                /* accounts= */ AccountMap{});
+  }
 }
 
 // static
@@ -520,11 +540,12 @@
 }
 
 void AccountManager::PersistAccountsAsync() {
-  if (!writer_) {
+  if (IsEphemeralMode()) {
     return;
   }
 
   // Schedule (immediately) a non-blocking write.
+  DCHECK(writer_);
   writer_->WriteNow(std::make_unique<std::string>(GetSerializedAccounts()));
 }
 
@@ -656,6 +677,10 @@
   }
 }
 
+bool AccountManager::IsEphemeralMode() const {
+  return home_dir_.empty();
+}
+
 COMPONENT_EXPORT(ACCOUNT_MANAGER)
 std::ostream& operator<<(std::ostream& os,
                          const AccountManager::AccountKey& account_key) {
diff --git a/chromeos/components/account_manager/account_manager.h b/chromeos/components/account_manager/account_manager.h
index 1f302ddd..bcbb72a 100644
--- a/chromeos/components/account_manager/account_manager.h
+++ b/chromeos/components/account_manager/account_manager.h
@@ -151,6 +151,12 @@
       DelayNetworkCallRunner delay_network_call_runner,
       base::OnceClosure initialization_callback);
 
+  // Initializes |AccountManager| for ephemeral / in-memory usage.
+  // Useful for tests that cannot afford to write to disk and clean up after
+  // themselves.
+  void InitializeInEphemeralMode(
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+
   // Returns |true| if |AccountManager| has been fully initialized.
   bool IsInitialized() const;
 
@@ -356,6 +362,10 @@
   // Deletes |request| from |pending_token_revocation_requests_|, if present.
   void DeletePendingTokenRevocationRequest(GaiaTokenRevocationRequest* request);
 
+  // Returns |true| if |AccountManager| is operating in ephemeral / in-memory
+  // mode, and not persisting anything to disk.
+  bool IsEphemeralMode() const;
+
   // Status of this object's initialization.
   InitializationState init_state_ = InitializationState::kNotStarted;
 
@@ -371,13 +381,16 @@
   PrefService* pref_service_ = nullptr;
 
   // A task runner for disk I/O.
+  // Will be |nullptr| if |AccountManager| is operating in ephemeral mode.
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
-  // Writes |AccountManager|'s state to disk. Will be |nullptr| if
-  // |AccountManager| is operating in-memory only.
+  // Writes |AccountManager|'s state to disk.
+  // Will be |nullptr| if |AccountManager| is operating in ephemeral mode.
   std::unique_ptr<base::ImportantFileWriter> writer_;
 
   // Cryptohome root.
+  // Will be |base::FilePath::empty()| if |AccountManager| is operating in
+  // ephemeral mode.
   base::FilePath home_dir_;
 
   // A map from |AccountKey|s to |AccountInfo|.
diff --git a/chromeos/components/account_manager/account_manager_unittest.cc b/chromeos/components/account_manager/account_manager_unittest.cc
index 9e66e4e..6e2813de 100644
--- a/chromeos/components/account_manager/account_manager_unittest.cc
+++ b/chromeos/components/account_manager/account_manager_unittest.cc
@@ -151,6 +151,15 @@
                              std::move(initialization_callback));
   }
 
+  // |account_manager| is a non-owning pointer.
+  void InitializeEphemeralAccountManager(AccountManager* account_manager) {
+    account_manager->InitializeInEphemeralMode(
+        test_url_loader_factory_.GetSafeWeakWrapper());
+    account_manager->SetPrefService(&pref_service_);
+    RunAllPendingTasks();
+    EXPECT_TRUE(account_manager->IsInitialized());
+  }
+
   void RunAllPendingTasks() { task_environment_.RunUntilIdle(); }
 
   // Returns an unowned pointer to |AccountManager|.
@@ -358,6 +367,24 @@
   EXPECT_EQ(0UL, accounts.size());
 }
 
+TEST_F(AccountManagerTest, TestEphemeralMode) {
+  {
+    // Create a scoped |AccountManager|.
+    AccountManager account_manager;
+    InitializeEphemeralAccountManager(&account_manager);
+    account_manager.UpsertAccount(kGaiaAccountKey, kRawUserEmail, kGaiaToken);
+    RunAllPendingTasks();
+  }
+
+  // Create another |AccountManager|.
+  AccountManager account_manager;
+  InitializeEphemeralAccountManager(&account_manager);
+
+  std::vector<AccountManager::Account> accounts =
+      GetAccountsBlocking(&account_manager);
+  EXPECT_EQ(0UL, accounts.size());
+}
+
 TEST_F(AccountManagerTest, TestAccountEmailPersistence) {
   account_manager()->UpsertAccount(kGaiaAccountKey, kRawUserEmail, kGaiaToken);
   RunAllPendingTasks();
diff --git a/chromeos/components/telemetry_extension_ui/mojom/probe_service.mojom b/chromeos/components/telemetry_extension_ui/mojom/probe_service.mojom
index c55401d..ad956a56e 100644
--- a/chromeos/components/telemetry_extension_ui/mojom/probe_service.mojom
+++ b/chromeos/components/telemetry_extension_ui/mojom/probe_service.mojom
@@ -37,10 +37,11 @@
 //      3.2) use string to store serial in a decimal numeral system instead
 //           of uint32 in case we want to extend serial number range.
 //   4) LogicalCpuInfo:
-//      4.1) rename idle_time_user_hz to idle_time_user, because of typo in
-//           cros_healthd interface;
-//      4.2) use uint64 to store idle_time_user instead of uint32,
-//           idle_time_user can easily be more than uint32 range.
+//      4.1) rename idle_time_user_hz to idle_time_ms and use milliseconds
+//           instead of USER_HZ units, because USER_HZ system constant is not
+//           available in the web.
+//      4.2) use uint64 to store idle_time_ms instead of uint32, idle_time_ms
+//           can easily be more than uint32 range.
 //   5) MemoryInfo: use uint64 to store page_faults_since_last_boot instead of
 //      uint32, it can be more than uint32 range.
 
@@ -252,9 +253,8 @@
   UInt32Value? scaling_max_frequency_khz;
   // Current frequency the CPU is running at.
   UInt32Value? scaling_current_frequency_khz;
-  // Idle time since last boot. USER_HZ can be converted to seconds
-  // with the conversion factor given by sysconf(_SC_CLK_TCK).
-  UInt64Value? idle_time_user;
+  // Idle time since last boot, in milliseconds.
+  UInt64Value? idle_time_ms;
   // Information about the logical CPU's time in various C-states.
   array<CpuCStateInfo> c_states;
 };
diff --git a/chromeos/components/telemetry_extension_ui/probe_service_converters.cc b/chromeos/components/telemetry_extension_ui/probe_service_converters.cc
index 6c3bb00..d6ec5de 100644
--- a/chromeos/components/telemetry_extension_ui/probe_service_converters.cc
+++ b/chromeos/components/telemetry_extension_ui/probe_service_converters.cc
@@ -4,6 +4,7 @@
 
 #include "chromeos/components/telemetry_extension_ui/probe_service_converters.h"
 
+#include <unistd.h>
 #include <utility>
 
 #include "base/notreached.h"
@@ -138,13 +139,34 @@
       std::move(input->name), Convert(input->time_in_state_since_last_boot_us));
 }
 
+namespace {
+
+uint64_t UserHz() {
+  const long user_hz = sysconf(_SC_CLK_TCK);
+  DCHECK(user_hz >= 0);
+  return user_hz;
+}
+
+}  // namespace
+
 health::mojom::LogicalCpuInfoPtr UncheckedConvertPtr(
     cros_healthd::mojom::LogicalCpuInfoPtr input) {
+  return UncheckedConvertPtr(std::move(input), UserHz());
+}
+
+health::mojom::LogicalCpuInfoPtr UncheckedConvertPtr(
+    cros_healthd::mojom::LogicalCpuInfoPtr input,
+    uint64_t user_hz) {
+  constexpr uint64_t kMillisecondsInSecond = 1000;
+  uint64_t idle_time_user_hz = static_cast<uint64_t>(input->idle_time_user_hz);
+
+  DCHECK(user_hz != 0);
+
   return health::mojom::LogicalCpuInfo::New(
       Convert(input->max_clock_speed_khz),
       Convert(input->scaling_max_frequency_khz),
       Convert(input->scaling_current_frequency_khz),
-      Convert(static_cast<uint64_t>(input->idle_time_user_hz)),
+      Convert(idle_time_user_hz * kMillisecondsInSecond / user_hz),
       ConvertPtrVector<health::mojom::CpuCStateInfoPtr>(
           std::move(input->c_states)));
 }
diff --git a/chromeos/components/telemetry_extension_ui/probe_service_converters.h b/chromeos/components/telemetry_extension_ui/probe_service_converters.h
index 504dd98..dbc68967 100644
--- a/chromeos/components/telemetry_extension_ui/probe_service_converters.h
+++ b/chromeos/components/telemetry_extension_ui/probe_service_converters.h
@@ -58,6 +58,10 @@
 health::mojom::LogicalCpuInfoPtr UncheckedConvertPtr(
     cros_healthd::mojom::LogicalCpuInfoPtr input);
 
+health::mojom::LogicalCpuInfoPtr UncheckedConvertPtr(
+    cros_healthd::mojom::LogicalCpuInfoPtr input,
+    uint64_t user_hz);
+
 health::mojom::PhysicalCpuInfoPtr UncheckedConvertPtr(
     cros_healthd::mojom::PhysicalCpuInfoPtr input);
 
diff --git a/chromeos/components/telemetry_extension_ui/probe_service_converters_unittest.cc b/chromeos/components/telemetry_extension_ui/probe_service_converters_unittest.cc
index 63bb790..09708ed 100644
--- a/chromeos/components/telemetry_extension_ui/probe_service_converters_unittest.cc
+++ b/chromeos/components/telemetry_extension_ui/probe_service_converters_unittest.cc
@@ -285,7 +285,10 @@
   constexpr uint32_t kMaxClockSpeedKhz = (1 << 31) + 10000;
   constexpr uint32_t kScalingMaxFrequencyKhz = (1 << 30) + 20000;
   constexpr uint32_t kScalingCurrentFrequencyKhz = (1 << 29) + 30000;
-  constexpr uint32_t kIdleTimeUserHz = (1 << 28) + 40000;
+
+  // Idle time cannot be tested with ConvertPtr, because it requires USER_HZ
+  // system constant to convert idle_time_user_hz to milliseconds.
+  constexpr uint32_t kIdleTime = 0;
 
   constexpr char kCpuCStateName[] = "C1";
   constexpr uint64_t kCpuCStateTime = (1 << 27) + 50000;
@@ -299,7 +302,7 @@
     input->max_clock_speed_khz = kMaxClockSpeedKhz;
     input->scaling_max_frequency_khz = kScalingMaxFrequencyKhz;
     input->scaling_current_frequency_khz = kScalingCurrentFrequencyKhz;
-    input->idle_time_user_hz = kIdleTimeUserHz;
+    input->idle_time_user_hz = kIdleTime;
     input->c_states.push_back(std::move(c_state));
   }
 
@@ -312,17 +315,33 @@
                 health::mojom::UInt32Value::New(kMaxClockSpeedKhz),
                 health::mojom::UInt32Value::New(kScalingMaxFrequencyKhz),
                 health::mojom::UInt32Value::New(kScalingCurrentFrequencyKhz),
-                health::mojom::UInt64Value::New(kIdleTimeUserHz),
+                health::mojom::UInt64Value::New(kIdleTime),
                 std::move(expected_c_states)));
 }
 
+TEST(ProbeServiceConvertors, LogicalCpuInfoPtrNonZeroIdleTime) {
+  constexpr uint64_t kUserHz = 100;
+  constexpr uint32_t kIdleTimeUserHz = 4291234295;
+  constexpr uint64_t kIdleTimeMs = 42912342950;
+
+  auto input = cros_healthd::mojom::LogicalCpuInfo::New();
+  input->idle_time_user_hz = kIdleTimeUserHz;
+
+  const auto output = unchecked::UncheckedConvertPtr(std::move(input), kUserHz);
+  ASSERT_TRUE(output);
+  EXPECT_EQ(output->idle_time_ms, health::mojom::UInt64Value::New(kIdleTimeMs));
+}
+
 TEST(ProbeServiceConvertors, PhysicalCpuInfoPtr) {
   constexpr char kModelName[] = "i9";
 
   constexpr uint32_t kMaxClockSpeedKhz = (1 << 31) + 11111;
   constexpr uint32_t kScalingMaxFrequencyKhz = (1 << 30) + 22222;
   constexpr uint32_t kScalingCurrentFrequencyKhz = (1 << 29) + 33333;
-  constexpr uint32_t kIdleTimeUserHz = (1 << 28) + 44444;
+
+  // Idle time cannot be tested with ConvertPtr, because it requires USER_HZ
+  // system constant to convert idle_time_user_hz to milliseconds.
+  constexpr uint32_t kIdleTime = 0;
 
   auto input = cros_healthd::mojom::PhysicalCpuInfo::New();
   {
@@ -330,7 +349,7 @@
     logical_info->max_clock_speed_khz = kMaxClockSpeedKhz;
     logical_info->scaling_max_frequency_khz = kScalingMaxFrequencyKhz;
     logical_info->scaling_current_frequency_khz = kScalingCurrentFrequencyKhz;
-    logical_info->idle_time_user_hz = kIdleTimeUserHz;
+    logical_info->idle_time_user_hz = kIdleTime;
 
     input->model_name = kModelName;
     input->logical_cpus.push_back(std::move(logical_info));
@@ -341,7 +360,7 @@
       health::mojom::UInt32Value::New(kMaxClockSpeedKhz),
       health::mojom::UInt32Value::New(kScalingMaxFrequencyKhz),
       health::mojom::UInt32Value::New(kScalingCurrentFrequencyKhz),
-      health::mojom::UInt64Value::New(kIdleTimeUserHz),
+      health::mojom::UInt64Value::New(kIdleTime),
       std::vector<health::mojom::CpuCStateInfoPtr>{}));
 
   EXPECT_EQ(ConvertPtr(std::move(input)),
diff --git a/chromeos/dbus/attestation/fake_attestation_client.h b/chromeos/dbus/attestation/fake_attestation_client.h
index 207e0a6..bb2748e 100644
--- a/chromeos/dbus/attestation/fake_attestation_client.h
+++ b/chromeos/dbus/attestation/fake_attestation_client.h
@@ -101,7 +101,7 @@
   AttestationClient::TestInterface* GetTestInterface() override;
 
  private:
-  bool is_prepared_{false};
+  bool is_prepared_ = true;
   std::deque<bool> preparation_sequences_;
 
   bool is_enrolled_ = false;
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 9d2ae5a..e3d8755 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -763,7 +763,6 @@
       "//components/gcm_driver/android:components_gcm_driver_junit_tests",
       "//components/permissions/android:components_permissions_junit_tests",
       "//components/policy/android:components_policy_junit_tests",
-      "//components/prefs/android:junit",
       "//components/query_tiles:query_tiles_junit_tests",
       "//components/signin/core/browser/android:components_signin_junit_tests",
       "//components/variations/android:components_variations_junit_tests",
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 25070c3..7f9eb32 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -88,6 +88,8 @@
     "data_model/autofill_profile.h",
     "data_model/autofill_profile_comparator.cc",
     "data_model/autofill_profile_comparator.h",
+    "data_model/autofill_structured_address_component.cc",
+    "data_model/autofill_structured_address_component.h",
     "data_model/autofill_structured_address_utils.cc",
     "data_model/autofill_structured_address_utils.h",
     "data_model/contact_info.cc",
@@ -568,6 +570,7 @@
     "data_model/autofill_data_model_unittest.cc",
     "data_model/autofill_profile_comparator_unittest.cc",
     "data_model/autofill_profile_unittest.cc",
+    "data_model/autofill_structured_address_component_unittest.cc",
     "data_model/autofill_structured_address_utils_unittest.cc",
     "data_model/contact_info_unittest.cc",
     "data_model/credit_card_unittest.cc",
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address_component.cc b/components/autofill/core/browser/data_model/autofill_structured_address_component.cc
new file mode 100644
index 0000000..424a182
--- /dev/null
+++ b/components/autofill/core/browser/data_model/autofill_structured_address_component.cc
@@ -0,0 +1,564 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/data_model/autofill_structured_address_component.h"
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/strings/strcat.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
+#include "components/autofill/core/browser/field_types.h"
+
+namespace autofill {
+
+namespace structured_address {
+AddressComponent::AddressComponent(ServerFieldType storage_type)
+    : AddressComponent(storage_type, nullptr, {}) {}
+
+AddressComponent::AddressComponent(ServerFieldType storage_type,
+                                   AddressComponent* parent)
+    : AddressComponent(storage_type, parent, {}) {}
+
+AddressComponent::AddressComponent(ServerFieldType storage_type,
+                                   AddressComponent* parent,
+                                   std::vector<AddressComponent*> subcomponents)
+    : value_verification_status_(VerificationStatus::kNoStatus),
+      storage_type_(storage_type),
+      subcomponents_(subcomponents),
+      parent_(parent) {}
+
+AddressComponent::~AddressComponent() = default;
+
+ServerFieldType AddressComponent::GetStorageType() const {
+  return storage_type_;
+}
+
+std::string AddressComponent::GetStorageTypeName() const {
+  return AutofillType(storage_type_).ToString();
+}
+
+AddressComponent& AddressComponent::operator=(const AddressComponent& right) {
+  DCHECK(GetStorageType() == right.GetStorageType());
+  if (this == &right)
+    return *this;
+
+  value_ = right.value_;
+  value_verification_status_ = right.value_verification_status_;
+
+  DCHECK(right.subcomponents_.size() == subcomponents_.size());
+
+  for (size_t i = 0; i < right.subcomponents_.size(); i++)
+    *subcomponents_[i] = *right.subcomponents_[i];
+
+  return *this;
+}
+
+bool AddressComponent::operator==(const AddressComponent& right) const {
+  if (this == &right)
+    return true;
+
+  if (GetStorageType() != right.GetStorageType())
+    return false;
+
+  if (value_ != right.value_ ||
+      value_verification_status_ != right.value_verification_status_)
+    return false;
+
+  DCHECK(right.subcomponents_.size() == subcomponents_.size());
+  for (size_t i = 0; i < right.subcomponents_.size(); i++)
+    if (!(*subcomponents_[i] == *right.subcomponents_[i]))
+      return false;
+  return true;
+}
+
+bool AddressComponent::operator!=(const AddressComponent& right) const {
+  return !(*this == right);
+}
+
+bool AddressComponent::IsAtomic() const {
+  return subcomponents_.empty();
+}
+
+VerificationStatus AddressComponent::GetVerificationStatus() const {
+  return value_verification_status_;
+}
+
+const base::string16& AddressComponent::GetValue() const {
+  if (value_.has_value())
+    return value_.value();
+  return base::EmptyString16();
+}
+
+bool AddressComponent::IsValueAssigned() const {
+  return value_.has_value();
+}
+
+void AddressComponent::SetValue(base::string16 value,
+                                VerificationStatus status) {
+  value_ = std::move(value);
+  value_verification_status_ = status;
+}
+
+void AddressComponent::UnsetValue() {
+  value_.reset();
+  value_verification_status_ = VerificationStatus::kNoStatus;
+}
+
+void AddressComponent::GetSupportedTypes(
+    ServerFieldTypeSet* supported_types) const {
+  // A proper AddressComponent tree contains every type only once.
+  DCHECK(supported_types->find(storage_type_) == supported_types->end())
+      << "The AddressComponent already contains a node that supports this "
+         "type: "
+      << storage_type_;
+  supported_types->insert(storage_type_);
+  GetAdditionalSupportedFieldTypes(supported_types);
+  for (auto* subcomponent : subcomponents_)
+    subcomponent->GetSupportedTypes(supported_types);
+}
+
+bool AddressComponent::ConvertAndSetValueForAdditionalFieldTypeName(
+    const std::string& field_type_name,
+    const base::string16& value,
+    const VerificationStatus& status) {
+  return false;
+}
+
+bool AddressComponent::ConvertAndGetTheValueForAdditionalFieldTypeName(
+    const std::string& field_type_name,
+    base::string16* value) const {
+  return false;
+}
+
+base::string16 AddressComponent::GetBestFormatString() const {
+  // If the component is atomic, the format string is just the value.
+  if (IsAtomic())
+    return base::ASCIIToUTF16(GetPlaceholderToken(GetStorageTypeName()));
+
+  // Otherwise, the canonical format string is the concatenation of all
+  // subcomponents by their natural order.
+  std::vector<std::string> format_pieces;
+  for (const auto* subcomponent : subcomponents_) {
+    std::string format_piece = GetPlaceholderToken(
+        AutofillType(subcomponent->GetStorageType()).ToString());
+    format_pieces.emplace_back(std::move(format_piece));
+  }
+  return base::ASCIIToUTF16(base::JoinString(format_pieces, " "));
+}
+
+std::vector<ServerFieldType> AddressComponent::GetSubcomponentTypes() const {
+  std::vector<ServerFieldType> subcomponent_types;
+  subcomponent_types.reserve(subcomponents_.size());
+  for (const auto* subcomponent : subcomponents_) {
+    subcomponent_types.emplace_back(subcomponent->GetStorageType());
+  }
+  return subcomponent_types;
+}
+
+bool AddressComponent::SetValueForTypeIfPossible(
+    const ServerFieldType& type,
+    const base::string16& value,
+    const VerificationStatus& verification_status,
+    bool invalidate_child_nodes,
+    bool invalidate_parent_nodes) {
+  return SetValueForTypeIfPossible(AutofillType(type).ToString(), value,
+                                   verification_status, invalidate_child_nodes,
+                                   invalidate_parent_nodes);
+}
+
+bool AddressComponent::SetValueForTypeIfPossible(
+    const std::string& type_name,
+    const base::string16& value,
+    const VerificationStatus& verification_status,
+    bool invalidate_child_nodes,
+    bool invalidate_parent_nodes) {
+  bool value_set = false;
+  // If the type is the storage type of the component, it can directly be
+  // returned.
+  if (type_name == GetStorageTypeName()) {
+    SetValue(value, verification_status);
+    value_set = true;
+  } else if (ConvertAndSetValueForAdditionalFieldTypeName(
+                 type_name, value, verification_status)) {
+    // The conversion using a field type was successful.
+    value_set = true;
+  }
+
+  if (value_set) {
+    if (invalidate_child_nodes)
+      UnsetSubcomponents();
+    return true;
+  }
+
+  // Finally, probe if the type is supported by one of the subcomponents.
+  for (auto* subcomponent : subcomponents_) {
+    if (subcomponent->SetValueForTypeIfPossible(
+            type_name, value, verification_status, invalidate_child_nodes,
+            invalidate_parent_nodes)) {
+      if (invalidate_parent_nodes)
+        UnsetValue();
+      return true;
+    }
+  }
+
+  return false;
+}
+
+void AddressComponent::UnsetAddressComponentAndItsSubcomponents() {
+  UnsetValue();
+  UnsetSubcomponents();
+}
+
+void AddressComponent::UnsetSubcomponents() {
+  for (auto* component : subcomponents_)
+    component->UnsetAddressComponentAndItsSubcomponents();
+}
+
+bool AddressComponent::GetValueAndStatusForTypeIfPossible(
+    const ServerFieldType& type,
+    base::string16* value,
+    VerificationStatus* status) const {
+  return GetValueAndStatusForTypeIfPossible(AutofillType(type).ToString(),
+                                            value, status);
+}
+
+bool AddressComponent::GetValueAndStatusForTypeIfPossible(
+    const std::string& type_name,
+    base::string16* value,
+    VerificationStatus* status) const {
+  // If the value is the storage type, it can be simply returned.
+  if (type_name == GetStorageTypeName()) {
+    if (value)
+      *value = value_.value_or(base::string16());
+    if (status)
+      *status = GetVerificationStatus();
+    return true;
+  }
+
+  // Otherwise, probe if it is a supported field type that can be converted.
+  if (this->ConvertAndGetTheValueForAdditionalFieldTypeName(type_name, value)) {
+    if (status)
+      *status = GetVerificationStatus();
+    return true;
+  }
+
+  // Finally, try to retrieve the value from one of the subcomponents.
+  for (const auto* subcomponent : subcomponents_) {
+    if (subcomponent->GetValueAndStatusForTypeIfPossible(type_name, value,
+                                                         status))
+      return true;
+  }
+  return false;
+}
+
+base::string16 AddressComponent::GetValueForType(
+    const ServerFieldType& type) const {
+  return GetValueForType(AutofillType(type).ToString());
+}
+
+base::string16 AddressComponent::GetValueForType(
+    const std::string& type_name) const {
+  base::string16 value;
+  bool success = GetValueAndStatusForTypeIfPossible(type_name, &value, nullptr);
+  DCHECK(success);
+  return value;
+}
+
+VerificationStatus AddressComponent::GetVerificationStatusForType(
+    const ServerFieldType& type) const {
+  return GetVerificationStatusForType(AutofillType(type).ToString());
+}
+
+VerificationStatus AddressComponent::GetVerificationStatusForType(
+    const std::string& type_name) const {
+  VerificationStatus status = VerificationStatus::kNoStatus;
+  bool success =
+      GetValueAndStatusForTypeIfPossible(type_name, nullptr, &status);
+  DCHECK(success);
+  return status;
+}
+
+bool AddressComponent::UnsetValueForTypeIfSupported(
+    const ServerFieldType& type) {
+  if (type == storage_type_) {
+    UnsetAddressComponentAndItsSubcomponents();
+    return true;
+  }
+
+  for (auto* subcomponent : subcomponents_) {
+    if (subcomponent->UnsetValueForTypeIfSupported(type))
+      return true;
+  }
+
+  return false;
+}
+
+bool AddressComponent::ParseValueAndAssignSubcomponentsByMethod() {
+  return false;
+}
+
+std::vector<const RE2*> AddressComponent::GetParseExpressionsByRelevance()
+    const {
+  return {};
+}
+
+void AddressComponent::ParseValueAndAssignSubcomponents() {
+  // Set the values of all subcomponents to the empty string and set the
+  // verification status to kParsed.
+  for (auto* subcomponent : subcomponents_)
+    subcomponent->SetValue(base::string16(), VerificationStatus::kParsed);
+
+  // First attempt, try to parse by method.
+  if (ParseValueAndAssignSubcomponentsByMethod())
+    return;
+
+  // Second attempt, try to parse by expressions.
+  if (ParseValueAndAssignSubcomponentsByExpressions())
+    return;
+
+  // As a final fallback, parse using the fallback method.
+  ParseValueAndAssignSubcomponentsByFallbackMethod();
+}
+
+bool AddressComponent::ParseValueAndAssignSubcomponentsByExpressions() {
+  for (const auto* parse_expression : GetParseExpressionsByRelevance()) {
+    if (!parse_expression)
+      continue;
+    std::map<std::string, std::string> result_map;
+    if (ParseValueByRegularExpression(base::UTF16ToUTF8(GetValue()),
+                                      parse_expression, &result_map)) {
+      // Parsing was successful and results from the result map can be written
+      // to the structure.
+      for (const auto& result_entry : result_map) {
+        std::string field_type = result_entry.first;
+        base::string16 field_value = base::UTF8ToUTF16(result_entry.second);
+        bool success = SetValueForTypeIfPossible(field_type, field_value,
+                                                 VerificationStatus::kParsed);
+        // Setting the value should always work unless the regular expression is
+        // invalid.
+        DCHECK(success);
+      }
+      return true;
+    }
+  }
+  return false;
+}
+
+void AddressComponent::ParseValueAndAssignSubcomponentsByFallbackMethod() {
+  // There is nothing to do for an atomic component.
+  if (IsAtomic())
+    return;
+
+  // An empty string is trivially parsable.
+  if (GetValue().empty())
+    return;
+
+  // Split the string by spaces.
+  std::vector<base::string16> space_separated_tokens =
+      base::SplitString(GetValue(), base::UTF8ToUTF16(" "),
+                        base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+  auto token_iterator = space_separated_tokens.begin();
+  auto subcomponent_types = GetSubcomponentTypes();
+
+  // Assign one space-separated token each to all but the last subcomponent.
+  for (size_t i = 0; (i + 1) < subcomponent_types.size(); i++) {
+    // If there are no tokens left, parsing is done.
+    if (token_iterator == space_separated_tokens.end())
+      return;
+    // Set the current token to the type and advance the token iterator.
+    bool success = SetValueForTypeIfPossible(
+        subcomponent_types[i], *token_iterator, VerificationStatus::kParsed);
+    // By design, setting the value should never fail.
+    DCHECK(success);
+    token_iterator++;
+  }
+
+  // Collect all remaining tokens in the last subcomponent.
+  base::string16 remaining_tokens = base::JoinString(
+      std::vector<base::string16>(token_iterator, space_separated_tokens.end()),
+      base::ASCIIToUTF16(" "));
+  // By design, it should be possible to assign the value unless the regular
+  // expression is wrong.
+  bool success = SetValueForTypeIfPossible(
+      subcomponent_types.back(), remaining_tokens, VerificationStatus::kParsed);
+  DCHECK(success);
+}
+
+void AddressComponent::FormatValueFromSubcomponents() {
+  // Get the most suited format string.
+  base::string16 format_string = GetBestFormatString();
+
+  // Perform the following steps on a copy of the format string.
+  // * Replace all the placeholders of the form ${TYPE_NAME} with the
+  // corresponding value.
+  // * Strip away double spaces as they may occur after replacing a placeholder
+  // with an empty value.
+
+  base::string16 result = ReplacePlaceholderTypesWithValues(format_string);
+  result = base::CollapseWhitespace(result, /*trim_line_breaks=*/false);
+  SetValue(result, VerificationStatus::kFormatted);
+}
+
+base::string16 AddressComponent::ReplacePlaceholderTypesWithValues(
+    const base::string16& format) const {
+  // Replaces placeholders using the following rules.
+  // Assumptions: Placeholder values are not nested.
+  //
+  // * Search for a substring of the form "{$[^}]*}".
+  //
+  // * Check if this substring is a supported type of this component.
+  //
+  // * If yes, replace the substring with the corresponding value.
+  //
+  // * If the corresponding value is empty, return false.
+
+  auto control_parmater = base::ASCIIToUTF16("$").at(0);
+  auto control_parmater_open_delimitor = base::ASCIIToUTF16("{").at(0);
+  auto control_parmater_close_delimitor = base::ASCIIToUTF16("}").at(0);
+
+  // Create a result vector for the tokens that are joined in the end.
+  std::vector<base::StringPiece16> result_pieces;
+  // Reserve space for 10 tokens. This should be sufficient for most cases.
+  result_pieces.reserve(10);
+
+  // Store the inserted values to allow the used StringPieces to stay valid.
+  std::vector<const base::string16> inserted_values;
+  inserted_values.reserve(4);
+
+  // Use a StringPiece rather than the string since this allows for getting
+  // cheap views onto substrings.
+  const base::StringPiece16 format_piece = format;
+
+  bool started_control_sequence = false;
+  // Track until which index the format string was fully processed.
+  size_t processed_until_index = 0;
+
+  for (size_t i = 0; i < format_piece.size(); ++i) {
+    // Check if a control sequence is started by '${'
+    if (format_piece[i] == control_parmater && i < format_piece.size() - 1 &&
+        format_piece[i + 1] == control_parmater_open_delimitor) {
+      // A control sequence is started.
+      started_control_sequence = true;
+      // Append the preceding string since it can't be a valid placeholder.
+      if (i > 0) {
+        result_pieces.emplace_back(format_piece.substr(
+            processed_until_index, i - processed_until_index));
+      }
+      processed_until_index = i;
+      ++i;
+    } else if (started_control_sequence &&
+               format_piece[i] == control_parmater_close_delimitor) {
+      // The control sequence came to an end.
+      started_control_sequence = false;
+      size_t placeholder_start = processed_until_index + 2;
+      base::string16 type_name =
+          format_piece.substr(placeholder_start, i - placeholder_start)
+              .as_string();
+      base::string16 value;
+      if (GetValueAndStatusForTypeIfPossible(base::UTF16ToASCII(type_name),
+                                             &value, nullptr)) {
+        // The type is valid and should be substituted.
+        inserted_values.emplace_back(std::move(value));
+        result_pieces.emplace_back(base::StringPiece16(inserted_values.back()));
+      } else {
+        // Append the control sequence as it is, because the type is not
+        // supported by the component tree.
+        result_pieces.emplace_back(format_piece.substr(
+            processed_until_index, i - processed_until_index + 1));
+      }
+      processed_until_index = i + 1;
+    }
+  }
+  // Append the rest of the string.
+  result_pieces.emplace_back(
+      format_piece.substr(processed_until_index, base::string16::npos));
+
+  // Build the final result.
+  return base::JoinString(result_pieces, base::ASCIIToUTF16(""));
+}
+
+bool AddressComponent::CompleteFullTree() {
+  if (!GetRootNode().IsTreeCompletable())
+    return false;
+  GetRootNode().RecursivelyCompleteTree();
+  return true;
+}
+
+void AddressComponent::RecursivelyCompleteTree() {
+  if (IsAtomic())
+    return;
+
+  // If the value is assigned, parse the subcomponents from the value.
+  if (IsValueAssigned())
+    ParseValueAndAssignSubcomponents();
+
+  // First call completion on all subcomponents.
+  for (auto* subcomponent : subcomponents_)
+    subcomponent->RecursivelyCompleteTree();
+
+  // Finally format the value from the sucomponents if it is not already
+  // assigned.
+  if (!IsValueAssigned())
+    FormatValueFromSubcomponents();
+}
+
+int AddressComponent::
+    MaximumNumberOfAssignedAddressComponentsOnNodeToLeafPaths() const {
+  int result = 0;
+
+  for (auto* subcomponent : subcomponents_) {
+    result = std::max(
+        result,
+        subcomponent
+            ->MaximumNumberOfAssignedAddressComponentsOnNodeToLeafPaths());
+  }
+
+  if (IsValueAssigned())
+    ++result;
+
+  return result;
+}
+
+bool AddressComponent::IsTreeCompletable() {
+  return MaximumNumberOfAssignedAddressComponentsOnNodeToLeafPaths() == 1;
+}
+
+const AddressComponent& AddressComponent::GetRootNode() const {
+  if (!parent_)
+    return *this;
+  return parent_->GetRootNode();
+}
+
+AddressComponent& AddressComponent::GetRootNode() {
+  return const_cast<AddressComponent&>(
+      const_cast<const AddressComponent*>(this)->GetRootNode());
+}
+
+void AddressComponent::RecursivelyUnsetParsedAndFormattedValues() {
+  if (IsValueAssigned() &&
+      (GetVerificationStatus() == VerificationStatus::kFormatted ||
+       GetVerificationStatus() == VerificationStatus::kParsed))
+    UnsetValue();
+
+  for (auto* component : subcomponents_)
+    component->RecursivelyUnsetParsedAndFormattedValues();
+}
+
+void AddressComponent::UnsetParsedAndFormattedValuesInEntireTree() {
+  GetRootNode().RecursivelyUnsetParsedAndFormattedValues();
+}
+
+}  // namespace structured_address
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address_component.h b/components/autofill/core/browser/data_model/autofill_structured_address_component.h
new file mode 100644
index 0000000..898bbf72
--- /dev/null
+++ b/components/autofill/core/browser/data_model/autofill_structured_address_component.h
@@ -0,0 +1,370 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_STRUCTURED_ADDRESS_COMPONENT_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_STRUCTURED_ADDRESS_COMPONENT_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/optional.h"
+#include "base/strings/string_piece.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "third_party/re2/src/re2/re2.h"
+
+namespace autofill {
+namespace structured_address {
+
+enum class VerificationStatus {
+  // No verification status assigned.
+  kNoStatus,
+  // The user used the autofill settings to verify and store this token.
+  kUserVerified,
+  // The value was observed in a form transmission.
+  kObserved,
+  // Value was built from its subcomponents.
+  kFormatted,
+  // The value token was parsed from a parent token.
+  kParsed,
+};
+
+// An AddressComponent is a tree structure that represents a semi-structured
+// address token. Such an address token can either be an atomic leaf node or
+// have a set of children, each representing a more granular subtoken of the
+// component.
+//
+// An AddressComponent has a string representation stored in |value_| and a
+// VerificationStatus stored in |verification_status_|.
+// The latter indicates if the value was user-verified, observed in a form
+// submission event, parsed from its parent component or was formatted from its
+// child components.
+//
+// In a proper component tree, each AddressComponent has a unique
+// ServerFieldType. Additionally, an AddressComponent may be associated with a
+// list of additional field types that allow for retrieving and setting the
+// Component's value in specific formats. For example, NAME_MIDDLE may be the
+// storage type and NAME_MIDDLE_INITIAL is an additional field type.
+//
+// The usage pattern of such an address tree is as follows:
+//
+//  * Create a tree from an observed form submission or a profile editing or
+//  creation event in the Chrome settings. It is assumed that the created
+//  tree does not have values for competing field types. Two types are competing
+//  iff they are on a common root-to-leaf path. For example, an imported profile
+//  with a value for NAME_FULL and NAME_LAST has conflicting types that
+//  carry redundant information.
+//
+//  * After the creation of the tree, the values of unassigned nodes in the tree
+//  are deducted from the values of assigned nodes. This happens by parsing
+//  (taking a string and splitting it into components) or by formatting (taking
+//  one or multiple strings and combining them into one string).
+//
+//  * After the completion, there should be no need to modify the tree.
+//
+//  * A tree may be mergeable with another tree of the same type. This
+//  operation incorporates complementing observations. For example, in the first
+//  tree NAME_FIRST, NAME_MIDDLE and NAME_LAST may be parsed from an observed
+//  unstructured name (NAME_FULL). The second tree may be built from observing
+//  the structured name, and contain observed NAME_FIRST, NAME_MIDDLE and
+//  NAME_LAST values but only a formatted NAME_FULL value.
+class AddressComponent {
+ public:
+  // Constructor for an atomic root node.
+  explicit AddressComponent(ServerFieldType storage_type);
+
+  // Constructor for an atomic leaf node.
+  explicit AddressComponent(ServerFieldType storage_type,
+                            AddressComponent* parent);
+
+  // Constructor for a compound child node.
+  AddressComponent(ServerFieldType storage_type,
+                   AddressComponent* parent,
+                   std::vector<AddressComponent*> subcomponents);
+
+  // Disallows copies since they are not needed in the current Autofill design.
+  AddressComponent(const AddressComponent& other) = delete;
+
+  virtual ~AddressComponent();
+
+  // Assignment operator that works recursively down the tree and assigns the
+  // |value_| and |verification_status_| of every node in right to the
+  // corresponding nodes in |this|. For an assignment it is required that both
+  // nodes have the same |storage_type_|.
+  AddressComponent& operator=(const AddressComponent& right);
+
+  // Comparison operator that works recursively down the tree.
+  bool operator==(const AddressComponent& right) const;
+
+  // Inequality operator that works recursively down the tree.
+  bool operator!=(const AddressComponent& right) const;
+
+  // Returns the autofill storage type stored in |storage_type_|.
+  ServerFieldType GetStorageType() const;
+
+  // Returns the string representation of |storage_type_|.
+  std::string GetStorageTypeName() const;
+
+  // Returns the value verification status of the component's value;
+  VerificationStatus GetVerificationStatus() const;
+
+  // Returns true if the component has no subcomponents.
+  bool IsAtomic() const;
+
+  // Returns a constant reference to |value_.value()|. If the value is not
+  // assigned, an empty string is returned.
+  const base::string16& GetValue() const;
+
+  // Returns true if the value of this AddressComponent is assigned.
+  bool IsValueAssigned() const;
+
+  // Sets the value corresponding to the storage type of this AddressComponent.
+  void SetValue(base::string16 value, VerificationStatus status);
+
+  // Sets the value to an empty string, marks it unassigned and sets the
+  // verification status to |kNoStatus|.
+  void UnsetValue();
+
+  // The method sets the value of the current node if its |storage_type_| is
+  // |type| or if |ConvertAndGetTheValueForAdditionalFieldTypeName()| supports
+  // retrieving |type|. Otherwise, the call is delegated recursively to the
+  // node's children.
+  // Returns true if the |value_| and |verification_status_| were successfully
+  // set for this or an ancestor node with the storage type |type|. If
+  // |invalidate_child_nodes|, all child nodes of the assigned node are
+  // unassigned. If |invalidate_parent_nodes|, all ancestor nodes of the
+  // assigned node as unassigned.
+  bool SetValueForTypeIfPossible(const ServerFieldType& type,
+                                 const base::string16& value,
+                                 const VerificationStatus& verification_status,
+                                 bool invalidate_child_nodes = false,
+                                 bool invalidate_parent_nodes = false);
+
+  // Same as |SetValueForTypeIfPossible()| but the type is supplied in the
+  // corresponding string representation.
+  bool SetValueForTypeIfPossible(const std::string& type_name,
+                                 const base::string16& value,
+                                 const VerificationStatus& verification_status,
+                                 bool invalidate_child_nodes = false,
+                                 bool invalidate_parent_nodes = false);
+
+  // Convenience method to get the value of |type|.
+  // Returns an empty string if |type| is not supported.
+  base::string16 GetValueForType(const ServerFieldType& type) const;
+
+  // Convenience method to get the value of |type| identified by its string
+  // representation name. Returns an empty string if |type| is not supported.
+  base::string16 GetValueForType(const std::string& type) const;
+
+  // Convenience method to get the verification status of |type|.
+  // Returns |VerificationStatus::kNoStatus| if |type| is not supported.
+  VerificationStatus GetVerificationStatusForType(
+      const ServerFieldType& type) const;
+
+  // Convenience method to get the verification status of |type| identified by
+  // its name. Returns |VerificationStatus::kNoStatus| if |type| is not
+  // supported.
+  VerificationStatus GetVerificationStatusForType(
+      const std::string& type) const;
+
+  // Get the value and status of a |type|,
+  // Returns false if the |type| is not supported by the structure.
+  // The method returns |value_| and |validation_status_| of the current node if
+  // its |storage_type_| is |type| or if
+  // |ConvertAndSetTheValueForAdditionalFieldTypeName()| supports setting
+  // |type|. Otherwise, the call is delegated recursively to the node's
+  // children. Returns false if the neither the node or one of its ancestors
+  // supports |type|.
+  bool GetValueAndStatusForTypeIfPossible(const ServerFieldType& type,
+                                          base::string16* value,
+                                          VerificationStatus* status) const;
+
+  // Get the value and status of a |type| identified by its name.
+  // Returns false if the |type| is not supported by the structure.
+  bool GetValueAndStatusForTypeIfPossible(const std::string& type_name,
+                                          base::string16* value,
+                                          VerificationStatus* status) const;
+
+  // Returns true if the |value| and |verification_status| were successfully
+  // unset for |type|.
+  bool UnsetValueForTypeIfSupported(const ServerFieldType& type);
+
+  // Parses |value_| to assign values to the subcomponents.
+  // The method uses 3 stages:
+  //
+  // * Use |ParseValueAndAssignSubcomponentsByMethod()|. This stage exists
+  // to catch special cases and may fail. The method is virtual and can be
+  // implemented on the type level.
+  //
+  // * Use |ParseValueAndAssignSubcomponentsByExpressions()|. This stage uses a
+  // list of regular expressions acquired by the virtual method
+  // |GetParseExpressionsByRelevance()|. This stage my fail.
+  //
+  // * Use |ParseValueAndAssignSubcomponentsByFallbackMethod()| as the last
+  // resort to parse |value_|. This method must produce a valid result.
+  void ParseValueAndAssignSubcomponents();
+
+  // This methods populated the unassigned entries in the subtree of this node
+  // by either parsing unknown values for subcomponents from their parents, or
+  // vice versa, formatting unknown values from known subcomponents. The method
+  // is virtual and can be reimplemented on the type level.
+  virtual void RecursivelyCompleteTree();
+
+  // Completes the full tree by calling |RecursivelyCompleteTree()| starting
+  // form the root node. Returns true if the completion was successful.
+  bool CompleteFullTree();
+
+  // Checks if a tree is completable in the sense that there are no conflicting
+  // observed or verified types. This means that there is not more than one
+  // observed or verified node on any root-to-leaf path in the tree.
+  bool IsTreeCompletable();
+
+  // Recursively adds the supported types to the set. Calls
+  // |GetAdditionalSupportedFieldTypes()| to add field types.
+  void GetSupportedTypes(ServerFieldTypeSet* supported_types) const;
+
+  // Adds the additional supported field types to |supported_types|.
+  // The method should DCHECK that the added types are not part of the set yet.
+  virtual void GetAdditionalSupportedFieldTypes(
+      ServerFieldTypeSet* supported_types) const {}
+
+  // Unassigns all nodes with parsed or formatted values.
+  void UnsetParsedAndFormattedValuesInEntireTree();
+
+  // Unassigns all nodes with parsed or formatted values.
+  void RecursivelyUnsetParsedAndFormattedValues();
+
+#ifdef UNIT_TEST
+  // Initiates the formatting of the values from the subcomponents.
+  void FormatValueFromSubcomponentsForTesting() {
+    FormatValueFromSubcomponents();
+  }
+
+  // Returns the best format string for testing.
+  base::string16 GetBestFormatStringForTesting() {
+    return GetBestFormatString();
+  }
+
+  // Returns the parse expressions by relevance for testing.
+  std::vector<const RE2*> GetParseExpressionsByRelevanceForTesting() {
+    return GetParseExpressionsByRelevance();
+  }
+
+  // Returns a reference to the root node of the tree for testing.
+  AddressComponent& GetRootNodeForTesting() { return GetRootNode(); }
+
+  // Replaces placeholder values in the best format string with the
+  // corresponding values.
+  base::string16 GetReplacedPlaceholderTypesWithValuesForTesting() const {
+    return ReplacePlaceholderTypesWithValues(GetBestFormatString());
+  }
+
+  // Returns a vector containing the |storage_types_| of all direct
+  // subcomponents.
+  std::vector<ServerFieldType> GetSubcomponentTypesForTesting() const {
+    return GetSubcomponentTypes();
+  }
+
+#endif
+
+ protected:
+  // Returns a vector containing the |storage_types_| of all direct
+  // subcomponents.
+  std::vector<ServerFieldType> GetSubcomponentTypes() const;
+
+  // Heuristic method to get the best suited format string.
+  // This method is virtual and can be reimplemented for each type.
+  virtual base::string16 GetBestFormatString() const;
+
+  // Returns pointers to regular expressions sorted by their relevance.
+  // This method is virtual and can be reimplemented for each type.
+  virtual std::vector<const RE2*> GetParseExpressionsByRelevance() const;
+
+  // Method to parse |value_| into the values of |subcomponents_|. The
+  // purpose of this method is to cover special cases. This method returns true
+  // on success and is allowed to fail. On failure, the |subcomponents_| are not
+  // altered.
+  virtual bool ParseValueAndAssignSubcomponentsByMethod();
+
+  // This method parses |value_| to assign values to the subcomponents.
+  // The method is virtual and can be reimplemented per type.
+  // It must succeed.
+  virtual void ParseValueAndAssignSubcomponentsByFallbackMethod();
+
+  // This method is used to set the value given by a type different than the
+  // storage type. It must implement the conversion logic specific to each type.
+  // It returns true if conversion logic exists and the type can be set.
+  virtual bool ConvertAndSetValueForAdditionalFieldTypeName(
+      const std::string& field_type_name,
+      const base::string16& value,
+      const VerificationStatus& status);
+
+  // This method is used to retrieve the value for a supported field type
+  // different from the storage type. It must implement the conversion logic
+  // specific to each type. It returns true if the type is supported and the
+  // value can be written back to value.
+  // The method must handle |nullptr|s for both the value and status.
+  virtual bool ConvertAndGetTheValueForAdditionalFieldTypeName(
+      const std::string& field_type_name,
+      base::string16* value) const;
+
+  // Clears all parsed and formatted values.
+  void ClearAllParsedAndFormattedValues();
+
+ private:
+  // Returns a reference to the constant root node of the tree.
+  const AddressComponent& GetRootNode() const;
+
+  // Returns a reference to the root node of the tree.
+  AddressComponent& GetRootNode();
+
+  // Unsets the node and all of its children.
+  void UnsetAddressComponentAndItsSubcomponents();
+
+  // Unsets the children of a node.
+  void UnsetSubcomponents();
+
+  // Determines the |value_| from the values of the subcomponents by using the
+  // most suitable format string determined by |GetBestFormatString()|.
+  void FormatValueFromSubcomponents();
+
+  // Replaces placeholder values with the corresponding values.
+  base::string16 ReplacePlaceholderTypesWithValues(
+      const base::string16& format) const;
+
+  // Replaces placeholder values with the corresponding values.
+  base::string16 ReplacePlaceholderTypesWithValuesRegexVersion(
+      const base::string16& format) const;
+
+  // This method uses regular expressions acquired by
+  // |GetParseExpressionsByRelevance| to parse |value_| into the values of the
+  // subcomponents. Returns true on success and is allowed to fail.
+  bool ParseValueAndAssignSubcomponentsByExpressions();
+
+  // Returns the maximum number of components with assigned values on the path
+  // from the component to a leaf node.
+  int MaximumNumberOfAssignedAddressComponentsOnNodeToLeafPaths() const;
+
+  // The unstructured value of this component.
+  base::Optional<base::string16> value_;
+
+  // The verification status of |value_| indicates the certainty of the value
+  // to be correct.
+  VerificationStatus value_verification_status_;
+
+  // The storable Autofill type of the component.
+  const ServerFieldType storage_type_;
+
+  // A vector of pointers to the subcomponents.
+  std::vector<AddressComponent*> subcomponents_;
+
+  // A pointer to the parent node. It is set to nullptr if the node is the root
+  // node of the AddressComponent tree.
+  AddressComponent* const parent_;
+};
+
+}  // namespace structured_address
+
+}  // namespace autofill
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_STRUCTURED_ADDRESS_COMPONENT_H_
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc b/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc
new file mode 100644
index 0000000..a585776
--- /dev/null
+++ b/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc
@@ -0,0 +1,1109 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/data_model/autofill_structured_address_component.h"
+
+#include <stddef.h>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/gtest_util.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::ASCIIToUTF16;
+
+namespace autofill {
+namespace structured_address {
+
+// Creates an atomic name component for testing purposes.
+class TestAtomicFirstNameAddressComponent : public AddressComponent {
+ public:
+  TestAtomicFirstNameAddressComponent()
+      : TestAtomicFirstNameAddressComponent(nullptr) {}
+  explicit TestAtomicFirstNameAddressComponent(AddressComponent* parent)
+      : AddressComponent(NAME_FIRST, parent) {}
+};
+
+class TestAtomicMiddleNameAddressComponent : public AddressComponent {
+ public:
+  TestAtomicMiddleNameAddressComponent()
+      : TestAtomicMiddleNameAddressComponent(nullptr) {}
+  explicit TestAtomicMiddleNameAddressComponent(AddressComponent* parent)
+      : AddressComponent(NAME_MIDDLE, parent) {}
+
+  void GetAdditionalSupportedFieldTypes(
+      ServerFieldTypeSet* supported_types) const override {
+    DCHECK(supported_types->find(NAME_MIDDLE_INITIAL) ==
+           supported_types->end());
+    supported_types->insert(NAME_MIDDLE_INITIAL);
+  }
+
+  bool ConvertAndSetValueForAdditionalFieldTypeName(
+      const std::string& field_type_name,
+      const base::string16& value,
+      const VerificationStatus& status) override {
+    if (field_type_name == AutofillType(NAME_MIDDLE_INITIAL).ToString()) {
+      SetValue(value, status);
+      return true;
+    }
+    return false;
+  }
+
+  bool ConvertAndGetTheValueForAdditionalFieldTypeName(
+      const std::string& field_type_name,
+      base::string16* value) const override {
+    if (field_type_name == AutofillType(NAME_MIDDLE_INITIAL).ToString()) {
+      if (value) {
+        *value = GetValue().substr(0, 1);
+      }
+      return true;
+    }
+    return false;
+  }
+};
+
+class TestAtomicLastNameAddressComponent : public AddressComponent {
+ public:
+  TestAtomicLastNameAddressComponent()
+      : TestAtomicLastNameAddressComponent(nullptr) {}
+  explicit TestAtomicLastNameAddressComponent(AddressComponent* parent)
+      : AddressComponent(NAME_LAST, parent) {}
+};
+
+// Creates a compound name for testing purposes.
+class TestCompoundNameAddressComponent : public AddressComponent {
+ public:
+  TestCompoundNameAddressComponent()
+      : TestCompoundNameAddressComponent(nullptr) {}
+  explicit TestCompoundNameAddressComponent(AddressComponent* parent)
+      : AddressComponent(NAME_FULL,
+                         parent,
+                         {&first_name_, &middle_name_, &last_name_}) {}
+
+  AddressComponent* GetFirstNameSubComponentForTesting() {
+    return &first_name_;
+  }
+
+ private:
+  TestAtomicFirstNameAddressComponent first_name_{this};
+  TestAtomicMiddleNameAddressComponent middle_name_{this};
+  TestAtomicLastNameAddressComponent last_name_{this};
+};
+
+// Creates a compound name for testing purposes that uses a method for parsing.
+class TestCompoundNameMethodParsedAddressComponent : public AddressComponent {
+ public:
+  TestCompoundNameMethodParsedAddressComponent()
+      : TestCompoundNameMethodParsedAddressComponent(nullptr) {}
+  explicit TestCompoundNameMethodParsedAddressComponent(
+      AddressComponent* parent)
+      : AddressComponent(NAME_FULL,
+                         parent,
+                         {&first_name_, &middle_name_, &last_name_}) {}
+
+  bool ParseValueAndAssignSubcomponentsByMethod() override {
+    // Assigns everything to the first name.
+    first_name_.SetValue(GetValue(), VerificationStatus::kParsed);
+    return true;
+  }
+
+ private:
+  TestAtomicFirstNameAddressComponent first_name_{this};
+  TestAtomicMiddleNameAddressComponent middle_name_{this};
+  TestAtomicLastNameAddressComponent last_name_{this};
+};
+
+// Creates a compound name for testing purposes that uses an expression to
+// parse.
+class TestCompoundNameExpressionParsedAddressComponent
+    : public AddressComponent {
+ public:
+  TestCompoundNameExpressionParsedAddressComponent()
+      : TestCompoundNameExpressionParsedAddressComponent(nullptr) {
+    expression1_ =
+        BuildExpressionFromPattern("(?P<NAME_FULL>(?P<NAME_MIDDLE>\\d*))");
+    expression2_ =
+        BuildExpressionFromPattern("(?P<NAME_FULL>(?P<NAME_LAST>.*))");
+  }
+  explicit TestCompoundNameExpressionParsedAddressComponent(
+      AddressComponent* parent)
+      : AddressComponent(NAME_FULL,
+                         parent,
+                         {&first_name_, &middle_name_, &last_name_}) {}
+
+  std::vector<const RE2*> GetParseExpressionsByRelevance() const override {
+    // The first two expressions will fail and the last one will be
+    // successful.
+    return {nullptr, expression1_.get(), expression2_.get()};
+  }
+
+ private:
+  std::unique_ptr<const RE2> expression1_;
+  std::unique_ptr<const RE2> expression2_;
+  TestAtomicFirstNameAddressComponent first_name_{this};
+  TestAtomicMiddleNameAddressComponent middle_name_{this};
+  TestAtomicLastNameAddressComponent last_name_{this};
+};
+
+// Creates a compound name with a custom format for testing purposes.
+class TestCompoundNameCustomFormatAddressComponent : public AddressComponent {
+ public:
+  TestCompoundNameCustomFormatAddressComponent()
+      : TestCompoundNameCustomFormatAddressComponent(nullptr) {}
+  explicit TestCompoundNameCustomFormatAddressComponent(
+      AddressComponent* parent)
+      : AddressComponent(NAME_FULL,
+                         parent,
+                         {&first_name, &middle_name, &last_name}) {}
+
+  // Introduces a custom format with a leading last name.
+  base::string16 GetBestFormatString() const override {
+    return base::ASCIIToUTF16("${NAME_LAST}, ${NAME_FIRST}");
+  }
+
+ private:
+  TestAtomicFirstNameAddressComponent first_name{this};
+  TestAtomicMiddleNameAddressComponent middle_name{this};
+  TestAtomicLastNameAddressComponent last_name{this};
+};
+
+// Creates a compound name with a custom format with unsupported token.
+class TestCompoundNameCustomFormatWithUnsupportedTokenAddressComponent
+    : public AddressComponent {
+ public:
+  TestCompoundNameCustomFormatWithUnsupportedTokenAddressComponent()
+      : TestCompoundNameCustomFormatWithUnsupportedTokenAddressComponent(
+            nullptr) {}
+  explicit TestCompoundNameCustomFormatWithUnsupportedTokenAddressComponent(
+      AddressComponent* parent)
+      : AddressComponent(NAME_FULL,
+                         parent,
+                         {&first_name, &middle_name, &last_name}) {}
+
+  // Introduce a custom format with a leading last name.
+  base::string16 GetBestFormatString() const override {
+    return base::ASCIIToUTF16("${NAME_LAST}, ${NAME_FIRST} ${NOT_SUPPORTED}");
+  }
+
+ private:
+  TestAtomicFirstNameAddressComponent first_name{this};
+  TestAtomicMiddleNameAddressComponent middle_name{this};
+  TestAtomicLastNameAddressComponent last_name{this};
+};
+
+class TestAtomicTitleAddressComponent : public AddressComponent {
+ public:
+  TestAtomicTitleAddressComponent()
+      : TestAtomicTitleAddressComponent(nullptr) {}
+  explicit TestAtomicTitleAddressComponent(AddressComponent* parent)
+      : AddressComponent(NAME_HONORIFIC_PREFIX, parent) {}
+};
+
+// Creates a fictional compound component with sub- and sub subcomponents.
+class TestCompoundNameWithTitleAddressComponent : public AddressComponent {
+ public:
+  TestCompoundNameWithTitleAddressComponent()
+      : TestCompoundNameWithTitleAddressComponent(nullptr) {}
+  explicit TestCompoundNameWithTitleAddressComponent(AddressComponent* parent)
+      : AddressComponent(CREDIT_CARD_NAME_FULL, parent, {&title, &full_name}) {}
+
+ private:
+  TestAtomicTitleAddressComponent title{this};
+  TestCompoundNameAddressComponent full_name{this};
+};
+
+// Creates a tree that is not proper in the sense that it contains the same type
+// multiple times.
+class TestNonProperFirstNameAddressComponent : public AddressComponent {
+ public:
+  TestNonProperFirstNameAddressComponent()
+      : TestNonProperFirstNameAddressComponent(nullptr) {}
+  explicit TestNonProperFirstNameAddressComponent(AddressComponent* parent)
+      : AddressComponent(NAME_FIRST, parent, {&second_name_first_node_}) {}
+
+ private:
+  TestAtomicFirstNameAddressComponent second_name_first_node_;
+};
+
+// Tests that the destructor does not crash
+TEST(AutofillStructuredAddressAddressComponent, ConstructAndDestruct) {
+  AddressComponent* component = new AddressComponent(NAME_FULL, nullptr);
+  delete component;
+  EXPECT_TRUE(true);
+}
+
+// Tests that a non-proper AddressComponent tree fails a DCHECK for
+// |GetSupportedTypes()|.
+TEST(AutofillStructuredAddressAddressComponent,
+     TestNonProperTreeDcheckFailure) {
+  TestNonProperFirstNameAddressComponent non_proper_compound;
+  ServerFieldTypeSet supported_tpyes;
+  EXPECT_DCHECK_DEATH(non_proper_compound.GetSupportedTypes(&supported_tpyes));
+}
+
+// Tests getting the root node.
+TEST(AutofillStructuredAddressAddressComponent, TestGetRootNode) {
+  TestCompoundNameAddressComponent compound_component;
+
+  // The root node should return the root node.
+  EXPECT_EQ(&compound_component, &(compound_component.GetRootNodeForTesting()));
+
+  // Get a pointer to a subcomponent, verify that it is not the root node and
+  // check that it successfully retrieves the root node.
+  AddressComponent* first_name_subcomponent_ptr =
+      compound_component.GetFirstNameSubComponentForTesting();
+  EXPECT_NE(&compound_component, first_name_subcomponent_ptr);
+  EXPECT_EQ(&compound_component,
+            &(first_name_subcomponent_ptr->GetRootNodeForTesting()));
+}
+
+// Tests that additional field types are correctly retrieved.
+TEST(AutofillStructuredAddressAddressComponent, TestGetSupportedFieldType) {
+  ServerFieldTypeSet field_type_set;
+
+  TestAtomicFirstNameAddressComponent first_name_component;
+  TestAtomicMiddleNameAddressComponent middle_name_component;
+
+  // The first name does not have an additional supported field type.
+  first_name_component.GetAdditionalSupportedFieldTypes(&field_type_set);
+  EXPECT_EQ(field_type_set, ServerFieldTypeSet({}));
+
+  // The middle name supports an iniital.
+  middle_name_component.GetAdditionalSupportedFieldTypes(&field_type_set);
+  EXPECT_EQ(field_type_set, ServerFieldTypeSet({NAME_MIDDLE_INITIAL}));
+}
+
+// Tests setting an additional field type.
+TEST(AutofillStructuredAddressAddressComponent, TestSetFieldTypeValue) {
+  TestCompoundNameAddressComponent compound_name;
+  EXPECT_TRUE(compound_name.SetValueForTypeIfPossible(
+      NAME_MIDDLE_INITIAL, base::UTF8ToUTF16("M"),
+      VerificationStatus::kObserved));
+
+  EXPECT_EQ(compound_name.GetValueForType(NAME_MIDDLE), base::UTF8ToUTF16("M"));
+}
+
+// Tests retrieving an additional field type.
+TEST(AutofillStructuredAddressAddressComponent, TestGetFieldTypeValue) {
+  TestCompoundNameAddressComponent compound_name;
+  EXPECT_TRUE(compound_name.SetValueForTypeIfPossible(
+      NAME_MIDDLE, base::UTF8ToUTF16("Middle"), VerificationStatus::kObserved));
+
+  EXPECT_EQ(compound_name.GetValueForType(NAME_MIDDLE_INITIAL),
+            base::UTF8ToUTF16("M"));
+  EXPECT_EQ(compound_name.GetVerificationStatusForType(NAME_MIDDLE_INITIAL),
+            VerificationStatus::kObserved);
+}
+
+// Tests adding all supported types to the set.
+TEST(AutofillStructuredAddressAddressComponent, TestGetSupportedTypes) {
+  ServerFieldTypeSet field_type_set;
+
+  TestAtomicFirstNameAddressComponent first_name_component;
+  TestAtomicMiddleNameAddressComponent middle_name_component;
+  TestCompoundNameAddressComponent compound_name;
+
+  // The first name only supports NAME_FIRST.
+  first_name_component.GetSupportedTypes(&field_type_set);
+  EXPECT_EQ(field_type_set, ServerFieldTypeSet({NAME_FIRST}));
+
+  // The middle name supports an initial.
+  field_type_set.clear();
+  middle_name_component.GetSupportedTypes(&field_type_set);
+  EXPECT_EQ(field_type_set,
+            ServerFieldTypeSet({NAME_MIDDLE, NAME_MIDDLE_INITIAL}));
+
+  // Verify that all types are added correctly in a compound structure.
+  field_type_set.clear();
+  compound_name.GetSupportedTypes(&field_type_set);
+  EXPECT_EQ(field_type_set,
+            ServerFieldTypeSet({NAME_MIDDLE, NAME_MIDDLE_INITIAL, NAME_FIRST,
+                                NAME_LAST, NAME_FULL}));
+}
+
+// Tests the comparison of thw atoms of the same type.
+TEST(AutofillStructuredAddressAddressComponent, TestComparisonOperator_Atom) {
+  AddressComponent left(NAME_FIRST);
+  AddressComponent right(NAME_FIRST);
+
+  left.SetValue(base::UTF8ToUTF16("some value"), VerificationStatus::kParsed);
+  right.SetValue(base::UTF8ToUTF16("some other value"),
+                 VerificationStatus::kFormatted);
+  EXPECT_NE(left.GetValue(), right.GetValue());
+  EXPECT_NE(left.GetVerificationStatus(), right.GetVerificationStatus());
+
+  EXPECT_FALSE(left == right);
+  EXPECT_TRUE(left != right);
+
+  right.SetValue(base::UTF8ToUTF16("some value"), VerificationStatus::kParsed);
+
+  EXPECT_TRUE(left == right);
+  EXPECT_FALSE(left != right);
+}
+
+// Tests comparison of two different types.
+TEST(AutofillStructuredAddressAddressComponent,
+     TestComparisonOperator_DifferentTypes) {
+  AddressComponent type_a1(NAME_FIRST);
+  AddressComponent type_a2(NAME_FIRST);
+  AddressComponent type_b(NAME_LAST);
+
+  EXPECT_TRUE(type_a1 == type_a2);
+  EXPECT_FALSE(type_a1 == type_b);
+}
+
+// Tests the comparison with itself.
+TEST(AutofillStructuredAddressAddressComponent,
+     TestComparisonOperator_SelfComparison) {
+  AddressComponent type_a(NAME_FIRST);
+
+  EXPECT_TRUE(type_a == type_a);
+}
+
+// Tests the comparison operator.
+TEST(AutofillStructuredAddressAddressComponent,
+     TestComparisonOperator_Compound) {
+  TestCompoundNameAddressComponent left;
+  TestCompoundNameAddressComponent right;
+
+  // Set left to a value and verify its state.
+  left.SetValueForTypeIfPossible(NAME_FULL,
+                                 base::UTF8ToUTF16("First Middle Last"),
+                                 VerificationStatus::kObserved);
+  EXPECT_TRUE(left.CompleteFullTree());
+  EXPECT_EQ(left.GetValueForType(NAME_FULL),
+            base::UTF8ToUTF16("First Middle Last"));
+  EXPECT_EQ(left.GetValueForType(NAME_FIRST), base::UTF8ToUTF16("First"));
+  EXPECT_EQ(left.GetValueForType(NAME_MIDDLE), base::UTF8ToUTF16("Middle"));
+  EXPECT_EQ(left.GetValueForType(NAME_LAST), base::UTF8ToUTF16("Last"));
+  EXPECT_EQ(left.GetVerificationStatusForType(NAME_FULL),
+            VerificationStatus::kObserved);
+  EXPECT_EQ(left.GetVerificationStatusForType(NAME_FIRST),
+            VerificationStatus::kParsed);
+  EXPECT_EQ(left.GetVerificationStatusForType(NAME_LAST),
+            VerificationStatus::kParsed);
+  EXPECT_EQ(left.GetVerificationStatusForType(NAME_MIDDLE),
+            VerificationStatus::kParsed);
+
+  // Set right to another value and verify its state.
+  right.SetValueForTypeIfPossible(NAME_FULL,
+                                  base::UTF8ToUTF16("The Dark Knight"),
+                                  VerificationStatus::kUserVerified);
+  EXPECT_TRUE(right.CompleteFullTree());
+  EXPECT_EQ(right.GetValueForType(NAME_FULL),
+            base::UTF8ToUTF16("The Dark Knight"));
+  EXPECT_EQ(right.GetValueForType(NAME_FIRST), base::UTF8ToUTF16("The"));
+  EXPECT_EQ(right.GetValueForType(NAME_MIDDLE), base::UTF8ToUTF16("Dark"));
+  EXPECT_EQ(right.GetValueForType(NAME_LAST), base::UTF8ToUTF16("Knight"));
+  EXPECT_EQ(right.GetVerificationStatusForType(NAME_FULL),
+            VerificationStatus::kUserVerified);
+  EXPECT_EQ(right.GetVerificationStatusForType(NAME_FIRST),
+            VerificationStatus::kParsed);
+  EXPECT_EQ(right.GetVerificationStatusForType(NAME_LAST),
+            VerificationStatus::kParsed);
+  EXPECT_EQ(right.GetVerificationStatusForType(NAME_MIDDLE),
+            VerificationStatus::kParsed);
+
+  EXPECT_FALSE(left == right);
+  EXPECT_TRUE(left != right);
+
+  // Set left to the same values as right and verify that it is now equal.
+  TestCompoundNameAddressComponent same_right;
+  same_right.SetValueForTypeIfPossible(NAME_FULL,
+                                       base::UTF8ToUTF16("The Dark Knight"),
+                                       VerificationStatus::kUserVerified);
+  EXPECT_TRUE(same_right.CompleteFullTree());
+
+  EXPECT_TRUE(right == same_right);
+  EXPECT_FALSE(right != same_right);
+
+  // Change one subcomponent and verify that it is not equal anymore.
+  same_right.SetValueForTypeIfPossible(NAME_LAST, base::UTF8ToUTF16("Joker"),
+                                       VerificationStatus::kParsed);
+  EXPECT_TRUE(right != same_right);
+  EXPECT_FALSE(right == same_right);
+}
+
+// Tests the assignment operator.
+TEST(AutofillStructuredAddressAddressComponent, TestAssignmentOperator_Atom) {
+  AddressComponent left(NAME_FIRST);
+  AddressComponent right(NAME_FIRST);
+
+  left.SetValue(base::UTF8ToUTF16("some value"), VerificationStatus::kParsed);
+  right.SetValue(base::UTF8ToUTF16("some other value"),
+                 VerificationStatus::kFormatted);
+  EXPECT_FALSE(left == right);
+
+  left.SetValue(base::UTF8ToUTF16("some other value"),
+                VerificationStatus::kFormatted);
+  EXPECT_TRUE(left == right);
+}
+
+// Tests the assignment operator on a compound node.
+TEST(AutofillStructuredAddressAddressComponent,
+     TestAssignmentOperator_Compound) {
+  TestCompoundNameAddressComponent left;
+  TestCompoundNameAddressComponent right;
+
+  left.SetValueForTypeIfPossible(NAME_FULL,
+                                 base::UTF8ToUTF16("First Middle Last"),
+                                 VerificationStatus::kObserved);
+  left.RecursivelyCompleteTree();
+
+  right.SetValueForTypeIfPossible(NAME_FULL,
+                                  base::UTF8ToUTF16("The Dark Knight"),
+                                  VerificationStatus::kParsed);
+  right.RecursivelyCompleteTree();
+
+  EXPECT_FALSE(left == right);
+
+  left = right;
+  EXPECT_TRUE(left == right);
+}
+
+// Tests that self-assignment does not break things.
+TEST(AutofillStructuredAddressAddressComponent, SelfAssignment) {
+  TestCompoundNameAddressComponent left;
+
+  left.SetValueForTypeIfPossible(NAME_FULL,
+                                 base::UTF8ToUTF16("First Middle Last"),
+                                 VerificationStatus::kObserved);
+  left = *(&left);
+
+  EXPECT_EQ(left.GetValueForType(NAME_FULL),
+            base::UTF8ToUTF16("First Middle Last"));
+}
+
+// Tests that the correct storage types are returned.
+TEST(AutofillStructuredAddressAddressComponent, GetStorageType) {
+  EXPECT_EQ(TestAtomicFirstNameAddressComponent().GetStorageType(), NAME_FIRST);
+  EXPECT_EQ(TestAtomicMiddleNameAddressComponent().GetStorageType(),
+            NAME_MIDDLE);
+  EXPECT_EQ(TestAtomicLastNameAddressComponent().GetStorageType(), NAME_LAST);
+  EXPECT_EQ(TestCompoundNameAddressComponent().GetStorageType(), NAME_FULL);
+}
+
+// Tests that the correct storage type names are returned.
+TEST(AutofillStructuredAddressAddressComponent, GetStorageTypeName) {
+  EXPECT_EQ(TestAtomicFirstNameAddressComponent().GetStorageTypeName(),
+            "NAME_FIRST");
+  EXPECT_EQ(TestAtomicMiddleNameAddressComponent().GetStorageTypeName(),
+            "NAME_MIDDLE");
+  EXPECT_EQ(TestAtomicLastNameAddressComponent().GetStorageTypeName(),
+            "NAME_LAST");
+  EXPECT_EQ(TestCompoundNameAddressComponent().GetStorageTypeName(),
+            "NAME_FULL");
+}
+
+// Tests that the correct atomicity is returned.
+TEST(AutofillStructuredAddressAddressComponent, GetAtomicity) {
+  EXPECT_TRUE(TestAtomicFirstNameAddressComponent().IsAtomic());
+  EXPECT_TRUE(TestAtomicMiddleNameAddressComponent().IsAtomic());
+  EXPECT_TRUE(TestAtomicLastNameAddressComponent().IsAtomic());
+  EXPECT_FALSE(TestCompoundNameAddressComponent().IsAtomic());
+}
+
+// Tests directly setting and retrieving values.
+TEST(AutofillStructuredAddressAddressComponent, DirectlyGetSetAndUnsetValue) {
+  base::string16 test_value = base::ASCIIToUTF16("test_value");
+
+  // Create an atomic structured component and verify its initial unset state
+  TestAtomicFirstNameAddressComponent first_name_component;
+  EXPECT_EQ(first_name_component.GetValue(), base::string16());
+  EXPECT_FALSE(first_name_component.IsValueAssigned());
+  EXPECT_EQ(first_name_component.GetVerificationStatus(),
+            VerificationStatus::kNoStatus);
+
+  // Set the value and the verification status and verify the set state.
+  first_name_component.SetValue(test_value, VerificationStatus::kObserved);
+  EXPECT_EQ(first_name_component.GetValue(), test_value);
+  EXPECT_TRUE(first_name_component.IsValueAssigned());
+  EXPECT_EQ(first_name_component.GetVerificationStatus(),
+            VerificationStatus::kObserved);
+
+  // Unset the value and verify the unset state again.
+  first_name_component.UnsetValue();
+  EXPECT_EQ(first_name_component.GetValue(), base::string16());
+  EXPECT_FALSE(first_name_component.IsValueAssigned());
+  EXPECT_EQ(first_name_component.GetVerificationStatus(),
+            VerificationStatus::kNoStatus);
+}
+
+// Tests recursively setting and retrieving values.
+TEST(AutofillStructuredAddressAddressComponent,
+     RecursivelySettingAndGettingValues) {
+  base::string16 test_value = base::ASCIIToUTF16("test_value");
+
+  // Create a compound component that has a child of type NAME_FIRST.
+  TestCompoundNameAddressComponent compound_component;
+
+  // Set the value and verification status of a type not present in the tree and
+  // verify the failure.
+  bool success = compound_component.SetValueForTypeIfPossible(
+      ADDRESS_HOME_COUNTRY, test_value, VerificationStatus::kObserved);
+  EXPECT_FALSE(success);
+
+  // Set the value and verification status of a type that is a subcomponent of
+  // the compound and verify the success.
+  EXPECT_TRUE(compound_component.SetValueForTypeIfPossible(
+      NAME_FIRST, test_value, VerificationStatus::kObserved));
+
+  // Retrieve the value and verification status, verify the success and
+  // retrieved values.
+  base::string16 retrieved_value;
+  VerificationStatus retrieved_status;
+  EXPECT_TRUE(compound_component.GetValueAndStatusForTypeIfPossible(
+      NAME_FIRST, &retrieved_value, &retrieved_status));
+  EXPECT_EQ(retrieved_value, test_value);
+  EXPECT_EQ(retrieved_status, VerificationStatus::kObserved);
+
+  // Retrieve the value of a non-existing type and verify the failure.
+  EXPECT_FALSE(compound_component.GetValueAndStatusForTypeIfPossible(
+      ADDRESS_HOME_COUNTRY, &retrieved_value, &retrieved_status));
+}
+
+// Tests retrieving the subcomponents types.
+TEST(AutofillStructuredAddressAddressComponent, GetSubcomponentTypes) {
+  // Create a compound component that has the subcomponents
+  // NAME_FIRST, NAME_MIDDLE, NAME_LAST.
+  TestCompoundNameAddressComponent compound_component;
+
+  // Get the subcomponent types and verify the expectation.
+  auto sub_component_types =
+      compound_component.GetSubcomponentTypesForTesting();
+  std::vector<ServerFieldType> expected_types{NAME_FIRST, NAME_MIDDLE,
+                                              NAME_LAST};
+  EXPECT_EQ(sub_component_types, expected_types);
+}
+
+// Tests getting the best format string for an atom.
+TEST(AutofillStructuredAddressAddressComponent, GetBestFormatString_ForAtom) {
+  TestAtomicFirstNameAddressComponent first_name_component;
+  EXPECT_EQ(first_name_component.GetBestFormatStringForTesting(),
+            base::UTF8ToUTF16("${NAME_FIRST}"));
+}
+
+// Tests getting the best format string using the fallback mechanism.
+TEST(AutofillStructuredAddressAddressComponent,
+     GetBestFormatString_WithFallback) {
+  // Create a compound component.
+  TestCompoundNameAddressComponent compound_component;
+
+  // Verify the retrieved default format string against the expectation.
+  base::string16 expected_result =
+      ASCIIToUTF16("${NAME_FIRST} ${NAME_MIDDLE} ${NAME_LAST}");
+  base::string16 actual_result =
+      compound_component.GetBestFormatStringForTesting();
+  EXPECT_EQ(expected_result, actual_result);
+}
+
+// Tests getting the best format string using the fallback mechanism.
+TEST(AutofillStructuredAddressAddressComponent,
+     GetBestFormatString_WithCustomMethod) {
+  // Create a compound component.
+  TestCompoundNameCustomFormatAddressComponent compound_component;
+
+  // Verify the retrieved custom format string against the expectation.
+  base::string16 expected_result = ASCIIToUTF16("${NAME_LAST}, ${NAME_FIRST}");
+  base::string16 actual_result =
+      compound_component.GetBestFormatStringForTesting();
+  EXPECT_EQ(expected_result, actual_result);
+}
+
+// Tests formatting the unstructured value from the subcomponents with an
+// unsupported token.
+TEST(AutofillStructuredAddressAddressComponent,
+     FormatValueFromSubcomponents_UnsupportedToken) {
+  base::string16 first_name = ASCIIToUTF16("Winston");
+  base::string16 middle_name = ASCIIToUTF16("O'Brien");
+  base::string16 last_name = ASCIIToUTF16("Smith");
+
+  // Create a compound component and set the values.
+  TestCompoundNameCustomFormatWithUnsupportedTokenAddressComponent
+      compound_component;
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FIRST, first_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_MIDDLE, middle_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_LAST, last_name, VerificationStatus::kUserVerified);
+
+  compound_component.FormatValueFromSubcomponentsForTesting();
+
+  base::string16 expected_value =
+      ASCIIToUTF16("Smith, Winston ${NOT_SUPPORTED}");
+  base::string16 actual_value = compound_component.GetValue();
+
+  EXPECT_EQ(expected_value, actual_value);
+}
+
+// Tests formatting the unstructured value from the subcomponents.
+TEST(AutofillStructuredAddressAddressComponent, FormatValueFromSubcomponents) {
+  base::string16 first_name = ASCIIToUTF16("Winston");
+  base::string16 middle_name = ASCIIToUTF16("O'Brien");
+  base::string16 last_name = ASCIIToUTF16("Smith");
+
+  // Create a compound component and set the values.
+  TestCompoundNameAddressComponent compound_component;
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FIRST, first_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_MIDDLE, middle_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_LAST, last_name, VerificationStatus::kUserVerified);
+
+  compound_component.FormatValueFromSubcomponentsForTesting();
+
+  base::string16 expected_value = ASCIIToUTF16("Winston O'Brien Smith");
+  base::string16 actual_value = compound_component.GetValue();
+
+  EXPECT_EQ(expected_value, actual_value);
+}
+
+// Tests that formatted values are correctly trimmed.
+TEST(AutofillStructuredAddressAddressComponent,
+     FormatAndTrimmValueFromSubcomponents) {
+  base::string16 first_name = ASCIIToUTF16("");
+  base::string16 middle_name = ASCIIToUTF16("O'Brien   ");
+  base::string16 last_name = ASCIIToUTF16("Smith");
+  // Create a compound component.
+  TestCompoundNameAddressComponent compound_component;
+
+  // Set the values of the components.
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FIRST, first_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_MIDDLE, middle_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_LAST, last_name, VerificationStatus::kUserVerified);
+
+  compound_component.FormatValueFromSubcomponentsForTesting();
+
+  // Expect that the leading whitespace due to the missing first name and the
+  // double white spaces after the middle name are correctly trimmed.
+  base::string16 expected_value = ASCIIToUTF16("O'Brien Smith");
+  base::string16 actual_value = compound_component.GetValue();
+
+  EXPECT_EQ(expected_value, actual_value);
+}
+
+TEST(AutofillStructuredAddressAddressComponent,
+     TestEquivalenceOfReplacePlaceholderImplementations) {
+  base::string16 first_name = ASCIIToUTF16("Winston");
+  base::string16 middle_name = ASCIIToUTF16("O'Brien");
+  base::string16 last_name = ASCIIToUTF16("Smith");
+  // Create a compound component.
+  TestCompoundNameCustomFormatAddressComponent compound_component;
+
+  // Set the values of the subcomponents.
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FIRST, first_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_MIDDLE, middle_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_LAST, last_name, VerificationStatus::kUserVerified);
+}
+
+// Tests the formatting of the unstructured value from the components with a
+// type-specific format string.
+TEST(AutofillStructuredAddressAddressComponent,
+     FormatValueFromSubcomponentsWithTypeSpecificFormat) {
+  base::string16 first_name = ASCIIToUTF16("Winston");
+  base::string16 middle_name = ASCIIToUTF16("O'Brien");
+  base::string16 last_name = ASCIIToUTF16("Smith");
+  // Create a compound component.
+  TestCompoundNameCustomFormatAddressComponent compound_component;
+
+  // Set the values of the subcomponents.
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FIRST, first_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_MIDDLE, middle_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_LAST, last_name, VerificationStatus::kUserVerified);
+
+  // Format the compound and verify the expectation.
+  compound_component.FormatValueFromSubcomponentsForTesting();
+  base::string16 expected_value = ASCIIToUTF16("Smith, Winston");
+  base::string16 actual_value = compound_component.GetValue();
+
+  EXPECT_EQ(expected_value, actual_value);
+}
+
+// Tests parsing of an empty value. Because, that's why.
+TEST(AutofillStructuredAddressAddressComponent,
+     TestParseValueAndAssignSubcomponentsByFallbackMethod_EmptyString) {
+  TestCompoundNameAddressComponent compound_component;
+  compound_component.SetValue(base::string16(), VerificationStatus::kObserved);
+  compound_component.ParseValueAndAssignSubcomponents();
+
+  EXPECT_EQ(compound_component.GetValue(), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
+}
+
+// Tests parsing using a defined method.
+TEST(AutofillStructuredAddressAddressComponent,
+     TestParseValueAndAssignSubcomponentsByMethod) {
+  TestCompoundNameMethodParsedAddressComponent compound_component;
+  compound_component.SetValue(ASCIIToUTF16("Dr. Strangelove"),
+                              VerificationStatus::kObserved);
+  compound_component.ParseValueAndAssignSubcomponents();
+
+  EXPECT_EQ(compound_component.GetValue(), ASCIIToUTF16("Dr. Strangelove"));
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST),
+            ASCIIToUTF16("Dr. Strangelove"));
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
+}
+
+// Tests parsing using a defined method.
+TEST(AutofillStructuredAddressAddressComponent,
+     TestParseValueAndAssignSubcomponentsByExpression) {
+  TestCompoundNameExpressionParsedAddressComponent compound_component;
+  compound_component.SetValue(ASCIIToUTF16("Dr. Strangelove"),
+                              VerificationStatus::kObserved);
+  compound_component.ParseValueAndAssignSubcomponents();
+
+  EXPECT_EQ(compound_component.GetValue(), ASCIIToUTF16("Dr. Strangelove"));
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST),
+            ASCIIToUTF16("Dr. Strangelove"));
+}
+
+// Go nuclear and parse the value of an atomic component.
+TEST(AutofillStructuredAddressAddressComponent,
+     TestParseValueAndAssignSubcomponentsByFallbackMethod_Atom) {
+  TestAtomicFirstNameAddressComponent atomic_component;
+  atomic_component.SetValue(base::UTF8ToUTF16("Dangerzone"),
+                            VerificationStatus::kObserved);
+  atomic_component.ParseValueAndAssignSubcomponents();
+
+  // The parsing should not crash the browser and keep the initial value intact.
+  EXPECT_EQ(base::UTF8ToUTF16("Dangerzone"), atomic_component.GetValue());
+}
+
+// Tests the fallback method to parse a value into its components if there are
+// more space-separated tokens than components.
+TEST(AutofillStructuredAddressAddressComponent,
+     TestParseValueAndAssignSubcomponentsByFallbackMethod) {
+  base::string16 full_name = ASCIIToUTF16("Winston O'Brien Hammer Smith");
+
+  // Create a compound component, set the value and parse the value of the
+  // subcomponents.
+  TestCompoundNameAddressComponent compound_component;
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FULL, full_name, VerificationStatus::kUserVerified);
+  compound_component.ParseValueAndAssignSubcomponents();
+
+  // Define the expectations, and verify the expectation.
+  base::string16 first_name = ASCIIToUTF16("Winston");
+  base::string16 middle_name = ASCIIToUTF16("O'Brien");
+  base::string16 last_name = ASCIIToUTF16("Hammer Smith");
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), first_name);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), middle_name);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), last_name);
+}
+
+// Tests the fallback method to parse a value into its components if there are
+// less space-separated tokens than components.
+TEST(AutofillStructuredAddressAddressComponent,
+     ParseValueAndAssignSubcomponentsByFallbackMethod_WithFewTokens) {
+  base::string16 full_name = ASCIIToUTF16("Winston");
+
+  // Create a compound component and assign a value.
+  TestCompoundNameAddressComponent compound_component;
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FULL, full_name, VerificationStatus::kUserVerified);
+
+  // Parse the full name into its components by using the fallback method
+  compound_component.ParseValueAndAssignSubcomponents();
+
+  // Verify the expectation.
+  base::string16 first_name = ASCIIToUTF16("Winston");
+  base::string16 middle_name = ASCIIToUTF16("");
+  base::string16 last_name = ASCIIToUTF16("");
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), first_name);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), middle_name);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), last_name);
+}
+
+// Tests that a tree is regarded completable if and only if there if the
+// maximum number of assigned nodes on a path from the root node to a leaf is
+// exactly one.
+TEST(AutofillStructuredAddressAddressComponent, IsTreeCompletable) {
+  // Some values.
+  base::string16 first_name = ASCIIToUTF16("Winston");
+  base::string16 middle_name = ASCIIToUTF16("O'Brien");
+  base::string16 full_name = ASCIIToUTF16("Winston O'Brien Smith");
+
+  // Create a compound component.
+  TestCompoundNameAddressComponent compound_component;
+
+  // This tree is not completable because it has not a single assigned node.
+  EXPECT_FALSE(compound_component.IsTreeCompletable());
+
+  // Set the first name node of the tree.
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FIRST, first_name, VerificationStatus::kUserVerified);
+
+  // The tree should be completable because there is exactly one assigned node.
+  EXPECT_TRUE(compound_component.IsTreeCompletable());
+
+  // Set the middle-name node of the tree.
+  compound_component.SetValueForTypeIfPossible(
+      NAME_MIDDLE, middle_name, VerificationStatus::kUserVerified);
+
+  // The tree should still be completable because the first and middle name are
+  // siblings and not in a direct line.
+  EXPECT_TRUE(compound_component.IsTreeCompletable());
+
+  // Set the full name node of the tree.
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FULL, full_name, VerificationStatus::kUserVerified);
+
+  // Now, the tree is not completable anymore because there are multiple
+  // assigned values on a path from the root to a leaf.
+  EXPECT_FALSE(compound_component.IsTreeCompletable());
+  EXPECT_FALSE(compound_component.CompleteFullTree());
+}
+
+// Tests that the tree is completed successfully from the root node down to the
+// leafs.
+TEST(AutofillStructuredAddressAddressComponent, TreeCompletion_TopToBottom) {
+  // Some values.
+  base::string16 first_name = ASCIIToUTF16("Winston");
+  base::string16 middle_name = ASCIIToUTF16("O'Brien");
+  base::string16 last_name = ASCIIToUTF16("Smith");
+  base::string16 full_name = ASCIIToUTF16("Winston O'Brien Smith");
+
+  // Create a compound component and set the value of the root node.
+  TestCompoundNameAddressComponent compound_component;
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FULL, full_name, VerificationStatus::kUserVerified);
+
+  // Verify that the are subcomponents empty.
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
+
+  // Complete the tree.
+  EXPECT_TRUE(compound_component.CompleteFullTree());
+
+  // Verify that the values for the subcomponents have been successfully parsed.
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), first_name);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), middle_name);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), last_name);
+}
+
+// Tests that the tree is completed successfully from leaf nodes to the root.
+TEST(AutofillStructuredAddressAddressComponent, TreeCompletion_BottomToTop) {
+  // Some values.
+  base::string16 first_name = ASCIIToUTF16("Winston");
+  base::string16 middle_name = ASCIIToUTF16("O'Brien");
+  base::string16 last_name = ASCIIToUTF16("Smith");
+  base::string16 full_name = ASCIIToUTF16("Winston O'Brien Smith");
+
+  // Create a compound component and set the value of the first, middle and last
+  // name.
+  TestCompoundNameAddressComponent compound_component;
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FIRST, first_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_MIDDLE, middle_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_LAST, last_name, VerificationStatus::kUserVerified);
+
+  // Verify that the root node is empty.
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FULL), base::string16());
+
+  // Complete the tree.
+  compound_component.CompleteFullTree();
+
+  // Verify that the value for the root node was successfully formatted.
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FULL), full_name);
+}
+
+// Tests that the tree is completed successfully both upwards and downwards when
+// a node with both subcomponents and a parent is set.
+TEST(AutofillStructuredAddressAddressComponent, TreeCompletion_ToTopAndBottom) {
+  // Define Some values.
+  base::string16 title = ASCIIToUTF16("Dr.");
+  base::string16 first_name = ASCIIToUTF16("Winston");
+  base::string16 middle_name = ASCIIToUTF16("O'Brien");
+  base::string16 last_name = ASCIIToUTF16("Smith");
+  base::string16 full_name = ASCIIToUTF16("Winston O'Brien Smith");
+  base::string16 full_name_with_title =
+      ASCIIToUTF16("Dr. Winston O'Brien Smith");
+
+  // Create a compound component.
+  TestCompoundNameWithTitleAddressComponent compound_component;
+
+  // Set the value of the root node.
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FULL, full_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_HONORIFIC_PREFIX, title, VerificationStatus::kUserVerified);
+
+  // Verify that the are subcomponents empty.
+  // CREDIT_CARD_NAME_FULL is a fictive type containing a title and a full name.
+  EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
+            base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
+
+  // Complete the tree.
+  compound_component.CompleteFullTree();
+
+  // Verify that the values for the subcomponents have been successfully parsed
+  // and the parent node was probably formatted.
+  EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
+            full_name_with_title);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), first_name);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), middle_name);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), last_name);
+}
+
+// Test that values are invalidated correctly.
+TEST(AutofillStructuredAddressAddressComponent,
+     TestSettingsValuesWithInvalidation) {
+  // Define Some values.
+  base::string16 title = ASCIIToUTF16("Dr.");
+  base::string16 first_name = ASCIIToUTF16("Winston");
+  base::string16 middle_name = ASCIIToUTF16("O'Brien");
+  base::string16 last_name = ASCIIToUTF16("Smith");
+  base::string16 full_name = ASCIIToUTF16("Winston O'Brien Smith");
+  base::string16 full_name_with_title =
+      ASCIIToUTF16("Dr. Winston O'Brien Smith");
+
+  // Create a compound component.
+  TestCompoundNameWithTitleAddressComponent compound_component;
+
+  // Set the value of the root node.
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FULL, full_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_HONORIFIC_PREFIX, title, VerificationStatus::kUserVerified);
+
+  // Verify that the are subcomponents empty.
+  // CREDIT_CARD_NAME_FULL is a fictive type containing a title and a full name.
+  EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
+            base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
+
+  // Complete the tree.
+  compound_component.CompleteFullTree();
+
+  // Verify that the values for the subcomponents have been successfully parsed
+  // and the parent node was probably formatted.
+  EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
+            full_name_with_title);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), first_name);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), middle_name);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), last_name);
+
+  // Change the value of FULL_NAME and invalidate all child and ancestor nodes.
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FULL, base::UTF8ToUTF16("Oh' Brian"), VerificationStatus::kObserved,
+      true, true);
+  EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
+            base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
+}
+
+// Test unsetting a value and its subcomponents.
+TEST(AutofillStructuredAddressAddressComponent,
+     TestUnsettingAValueAndItsSubcomponents) {
+  // Define Some values.
+  base::string16 title = ASCIIToUTF16("Dr.");
+  base::string16 first_name = ASCIIToUTF16("Winston");
+  base::string16 middle_name = ASCIIToUTF16("O'Brien");
+  base::string16 last_name = ASCIIToUTF16("Smith");
+  base::string16 full_name = ASCIIToUTF16("Winston O'Brien Smith");
+  base::string16 full_name_with_title =
+      ASCIIToUTF16("Dr. Winston O'Brien Smith");
+
+  // Create a compound component.
+  TestCompoundNameWithTitleAddressComponent compound_component;
+
+  // Set the value of the root node.
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FULL, full_name, VerificationStatus::kUserVerified);
+  compound_component.SetValueForTypeIfPossible(
+      NAME_HONORIFIC_PREFIX, title, VerificationStatus::kUserVerified);
+
+  // Verify that the are subcomponents empty.
+  // CREDIT_CARD_NAME_FULL is a fictive type containing a title and a full name.
+  EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
+            base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
+
+  // Complete the tree.
+  compound_component.CompleteFullTree();
+
+  // Verify that the values for the subcomponents have been successfully parsed
+  // and the parent node was probably formatted.
+  EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
+            full_name_with_title);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), first_name);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), middle_name);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), last_name);
+
+  // Change the value of FULL_NAME and invalidate all child and ancestor nodes.
+  compound_component.UnsetValueForTypeIfSupported(NAME_FULL);
+  EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
+            full_name_with_title);
+  EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
+  EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
+}
+
+// Tests that the tree is completed successfully both upwards and downwards when
+// a node with both subcomponents and a parent is set.
+TEST(AutofillStructuredAddressAddressComponent,
+     TestUnsettingParsedAndFormatedValues) {
+  // Define Some values.
+
+  TestCompoundNameWithTitleAddressComponent compound_component;
+
+  // Set a value somewhere in the tree, complete and verify that another node is
+  // assigned.
+  compound_component.SetValueForTypeIfPossible(
+      NAME_FULL, base::UTF8ToUTF16("Winston Brian Smith"),
+      VerificationStatus::kObserved);
+  EXPECT_EQ(VerificationStatus::kObserved,
+            compound_component.GetVerificationStatusForType(NAME_FULL));
+  compound_component.CompleteFullTree();
+  EXPECT_EQ(VerificationStatus::kParsed,
+            compound_component.GetVerificationStatusForType(NAME_MIDDLE));
+  EXPECT_EQ(
+      VerificationStatus::kFormatted,
+      compound_component.GetVerificationStatusForType(CREDIT_CARD_NAME_FULL));
+
+  // Clear parsed and formatted values and verify the expectation.
+  compound_component.UnsetParsedAndFormattedValuesInEntireTree();
+  EXPECT_EQ(VerificationStatus::kObserved,
+            compound_component.GetVerificationStatusForType(NAME_FULL));
+  EXPECT_EQ(VerificationStatus::kNoStatus,
+            compound_component.GetVerificationStatusForType(NAME_MIDDLE));
+  EXPECT_EQ(
+      VerificationStatus::kNoStatus,
+      compound_component.GetVerificationStatusForType(CREDIT_CARD_NAME_FULL));
+}
+
+}  // namespace structured_address
+}  // namespace autofill
diff --git a/components/autofill_assistant/browser/actions/show_generic_ui_action.cc b/components/autofill_assistant/browser/actions/show_generic_ui_action.cc
index 6f66a26..28f2b505 100644
--- a/components/autofill_assistant/browser/actions/show_generic_ui_action.cc
+++ b/components/autofill_assistant/browser/actions/show_generic_ui_action.cc
@@ -118,8 +118,15 @@
     }
   }
 
+  base::OnceCallback<void()> end_on_navigation_callback;
+  if (proto_.show_generic_ui().end_on_navigation()) {
+    end_on_navigation_callback =
+        base::BindOnce(&ShowGenericUiAction::OnNavigationEnded,
+                       weak_ptr_factory_.GetWeakPtr());
+  }
   delegate_->Prompt(/* user_actions = */ nullptr,
-                    /* disable_force_expand_sheet = */ false);
+                    /* disable_force_expand_sheet = */ false,
+                    std::move(end_on_navigation_callback));
   delegate_->SetGenericUi(
       std::make_unique<GenericUserInterfaceProto>(
           proto_.show_generic_ui().generic_user_interface()),
@@ -166,12 +173,13 @@
     preconditions_.emplace_back(std::make_unique<ElementPrecondition>(
         element_check.element_condition()));
   }
-  if (std::any_of(
+  if (proto_.show_generic_ui().allow_interrupt() ||
+      std::any_of(
           preconditions_.begin(), preconditions_.end(),
           [&](const auto& precondition) { return !precondition->empty(); })) {
     has_pending_wait_for_dom_ = true;
     delegate_->WaitForDom(
-        base::TimeDelta::Max(), false,
+        base::TimeDelta::Max(), proto_.show_generic_ui().allow_interrupt(),
         base::BindRepeating(&ShowGenericUiAction::RegisterChecks,
                             weak_ptr_factory_.GetWeakPtr()),
         base::BindOnce(&ShowGenericUiAction::OnDoneWaitForDom,
@@ -179,6 +187,12 @@
   }
 }
 
+void ShowGenericUiAction::OnNavigationEnded() {
+  processed_action_proto_->mutable_show_generic_ui_result()
+      ->set_navigation_ended(true);
+  OnEndActionInteraction(ClientStatus(ACTION_APPLIED));
+}
+
 void ShowGenericUiAction::RegisterChecks(
     BatchElementChecker* checker,
     base::OnceCallback<void(const ClientStatus&)> wait_for_dom_callback) {
@@ -203,6 +217,9 @@
     size_t precondition_index,
     const ClientStatus& status,
     const std::vector<std::string>& ignored_payloads) {
+  if (should_end_action_) {
+    return;
+  }
   delegate_->GetUserModel()->SetValue(proto_.show_generic_ui()
                                           .periodic_element_checks()
                                           .element_checks(precondition_index)
@@ -243,6 +260,12 @@
 }
 
 void ShowGenericUiAction::EndAction(const ClientStatus& status) {
+  if (!callback_) {
+    // Avoid race condition: it is possible that a breaking navigation event
+    // occurs immediately before or after the action would end naturally.
+    return;
+  }
+
   delegate_->ClearGenericUi();
   delegate_->CleanUpAfterPrompt();
   UpdateProcessedAction(status);
diff --git a/components/autofill_assistant/browser/actions/show_generic_ui_action.h b/components/autofill_assistant/browser/actions/show_generic_ui_action.h
index 5cdca28..f57505a 100644
--- a/components/autofill_assistant/browser/actions/show_generic_ui_action.h
+++ b/components/autofill_assistant/browser/actions/show_generic_ui_action.h
@@ -46,6 +46,7 @@
   void EndAction(const ClientStatus& status);
 
   void OnViewInflationFinished(const ClientStatus& status);
+  void OnNavigationEnded();
 
   // From autofill::PersonalDataManagerObserver.
   void OnPersonalDataChanged() override;
diff --git a/components/autofill_assistant/browser/actions/show_generic_ui_action_unittest.cc b/components/autofill_assistant/browser/actions/show_generic_ui_action_unittest.cc
index d0405c8..38f33b6 100644
--- a/components/autofill_assistant/browser/actions/show_generic_ui_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/show_generic_ui_action_unittest.cc
@@ -455,5 +455,72 @@
   Run();
 }
 
+TEST_F(ShowGenericUiActionTest, EndActionOnNavigation) {
+  ON_CALL(mock_action_delegate_, OnSetGenericUi(_, _, _))
+      .WillByDefault(
+          Invoke([&](std::unique_ptr<GenericUserInterfaceProto> generic_ui,
+                     base::OnceCallback<void(const ClientStatus&)>&
+                         end_action_callback,
+                     base::OnceCallback<void(const ClientStatus&)>&
+                         view_inflation_finished_callback) {
+            std::move(view_inflation_finished_callback)
+                .Run(ClientStatus(ACTION_APPLIED));
+          }));
+  EXPECT_CALL(mock_action_delegate_, Prompt(_, _, _, _))
+      .WillOnce(Invoke(
+          [](std::unique_ptr<std::vector<UserAction>> user_actions,
+             bool disable_force_expand_sheet,
+             base::OnceCallback<void()> end_navigation_callback,
+             bool browse_mode) { std::move(end_navigation_callback).Run(); }));
+  EXPECT_CALL(mock_action_delegate_, CleanUpAfterPrompt()).Times(1);
+  EXPECT_CALL(
+      callback_,
+      Run(Pointee(
+          AllOf(Property(&ProcessedActionProto::status, ACTION_APPLIED),
+                Property(&ProcessedActionProto::show_generic_ui_result,
+                         Property(&ShowGenericUiProto::Result::navigation_ended,
+                                  true))))));
+
+  proto_.set_end_on_navigation(true);
+  Run();
+}
+
+TEST_F(ShowGenericUiActionTest, BreakingNavigationBeforeUiIsSet) {
+  // End action immediately with ACTION_APPLIED after it goes into prompt.
+  EXPECT_CALL(mock_action_delegate_, Prompt(_, _, _, _))
+      .WillOnce(Invoke(
+          [](std::unique_ptr<std::vector<UserAction>> user_actions,
+             bool disable_force_expand_sheet,
+             base::OnceCallback<void()> end_navigation_callback,
+             bool browse_mode) { std::move(end_navigation_callback).Run(); }));
+  ON_CALL(mock_action_delegate_, OnSetGenericUi(_, _, _))
+      .WillByDefault(
+          Invoke([&](std::unique_ptr<GenericUserInterfaceProto> generic_ui,
+                     base::OnceCallback<void(const ClientStatus&)>&
+                         end_action_callback,
+                     base::OnceCallback<void(const ClientStatus&)>&
+                         view_inflation_finished_callback) {
+            std::move(view_inflation_finished_callback)
+                .Run(ClientStatus(ACTION_APPLIED));
+            // Also end action when UI is set. At this point, the action should
+            // have terminated already.
+            std::move(end_action_callback)
+                .Run(ClientStatus(OTHER_ACTION_STATUS));
+          }));
+  EXPECT_CALL(mock_action_delegate_, CleanUpAfterPrompt()).Times(1);
+  EXPECT_CALL(
+      callback_,
+      Run(Pointee(
+          AllOf(Property(&ProcessedActionProto::status, ACTION_APPLIED),
+                Property(&ProcessedActionProto::show_generic_ui_result,
+                         Property(&ShowGenericUiProto::Result::navigation_ended,
+                                  true))))));
+
+  proto_.set_end_on_navigation(true);
+  Run();
+}
+
+// TODO(b/161652848): Add test coverage for element checks and interrupts.
+
 }  // namespace
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/basic_interactions.cc b/components/autofill_assistant/browser/basic_interactions.cc
index e118082..b9e9ce2 100644
--- a/components/autofill_assistant/browser/basic_interactions.cc
+++ b/components/autofill_assistant/browser/basic_interactions.cc
@@ -245,6 +245,13 @@
                     ContainsClientOnlyValue({*value_a, *value_b})));
     return true;
   }
+  if (proto.mode() == ValueComparisonProto::NOT_EQUAL) {
+    user_model->SetValue(
+        result_model_identifier,
+        SimpleValue(*value_a != *value_b,
+                    ContainsClientOnlyValue({*value_a, *value_b})));
+    return true;
+  }
 
   // All modes except EQUAL require a size of 1 and a common value type and
   // are only supported for a subset of value types.
@@ -286,6 +293,7 @@
       result = *value_a > *value_b;
       break;
     case ValueComparisonProto::EQUAL:
+    case ValueComparisonProto::NOT_EQUAL:
     case ValueComparisonProto::UNDEFINED:
       NOTREACHED();
       return false;
diff --git a/components/autofill_assistant/browser/basic_interactions_unittest.cc b/components/autofill_assistant/browser/basic_interactions_unittest.cc
index 1eb98bdb..9d9e678 100644
--- a/components/autofill_assistant/browser/basic_interactions_unittest.cc
+++ b/components/autofill_assistant/browser/basic_interactions_unittest.cc
@@ -436,28 +436,32 @@
   proto.set_result_model_identifier("result");
   EXPECT_FALSE(basic_interactions_.ComputeValue(proto));
 
-  // EQUAL supported for all value types.
-  proto.mutable_comparison()->set_mode(ValueComparisonProto::EQUAL);
-  EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
-  user_model_.SetValue("value_a", SimpleValue(std::string("string_a")));
-  user_model_.SetValue("value_b", SimpleValue(std::string("string_b")));
-  EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
-  user_model_.SetValue("value_a", SimpleValue(true));
-  user_model_.SetValue("value_b", SimpleValue(false));
-  EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
-  user_model_.SetValue("value_a", SimpleValue(1));
-  user_model_.SetValue("value_b", SimpleValue(2));
-  EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
-  user_model_.SetValue("value_a", SimpleValue(CreateDateProto(2020, 8, 7)));
-  user_model_.SetValue("value_b", SimpleValue(CreateDateProto(2020, 11, 5)));
-  EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
-  ValueProto user_actions_value;
-  user_actions_value.mutable_user_actions();
-  user_model_.SetValue("value_a", user_actions_value);
-  user_model_.SetValue("value_b", user_actions_value);
-  EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+  // EQUAL and NOT_EQUAL supported for all value types.
+  ValueComparisonProto::Mode support_all_types_modes[] = {
+      ValueComparisonProto::EQUAL, ValueComparisonProto::NOT_EQUAL};
+  for (const auto mode : support_all_types_modes) {
+    proto.mutable_comparison()->set_mode(mode);
+    EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+    user_model_.SetValue("value_a", SimpleValue(std::string("string_a")));
+    user_model_.SetValue("value_b", SimpleValue(std::string("string_b")));
+    EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+    user_model_.SetValue("value_a", SimpleValue(true));
+    user_model_.SetValue("value_b", SimpleValue(false));
+    EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+    user_model_.SetValue("value_a", SimpleValue(1));
+    user_model_.SetValue("value_b", SimpleValue(2));
+    EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+    user_model_.SetValue("value_a", SimpleValue(CreateDateProto(2020, 8, 7)));
+    user_model_.SetValue("value_b", SimpleValue(CreateDateProto(2020, 11, 5)));
+    EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+    ValueProto user_actions_value;
+    user_actions_value.mutable_user_actions();
+    user_model_.SetValue("value_a", user_actions_value);
+    user_model_.SetValue("value_b", user_actions_value);
+    EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+  }
 
-  // Some types are not supported for comparison mode != EQUAL.
+  // Some types are not supported for modes other than EQUAL and NOT_EQUAL.
   proto.mutable_comparison()->set_mode(ValueComparisonProto::LESS);
   user_model_.SetValue("value_a", ValueProto());
   user_model_.SetValue("value_b", ValueProto());
@@ -465,6 +469,8 @@
   user_model_.SetValue("value_a", SimpleValue(true));
   user_model_.SetValue("value_b", SimpleValue(false));
   EXPECT_FALSE(basic_interactions_.ComputeValue(proto));
+  ValueProto user_actions_value;
+  user_actions_value.mutable_user_actions();
   user_model_.SetValue("value_a", user_actions_value);
   user_model_.SetValue("value_b", user_actions_value);
   EXPECT_FALSE(basic_interactions_.ComputeValue(proto));
@@ -482,6 +488,12 @@
   user_model_.SetValue("value_b", multi_value);
   EXPECT_FALSE(basic_interactions_.ComputeValue(proto));
 
+  // Different types succeed for mode == NOT_EQUAL.
+  proto.mutable_comparison()->set_mode(ValueComparisonProto::NOT_EQUAL);
+  user_model_.SetValue("value_a", SimpleValue(1));
+  user_model_.SetValue("value_b", SimpleValue(std::string("a")));
+  EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+
   // Check comparison results.
   proto.mutable_comparison()->set_mode(ValueComparisonProto::LESS);
   user_model_.SetValue("value_a", SimpleValue(1));
@@ -524,6 +536,21 @@
                        SimpleValue(1, /* is_client_side_only = */ true));
   EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
   EXPECT_EQ(*user_model_.GetValue("result"), SimpleValue(true, true));
+
+  proto.mutable_comparison()->set_mode(ValueComparisonProto::NOT_EQUAL);
+  user_model_.SetValue("value_a", SimpleValue(1));
+  user_model_.SetValue("value_b", SimpleValue(std::string("a")));
+  EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+  EXPECT_EQ(user_model_.GetValue("result"), SimpleValue(true));
+
+  user_model_.SetValue("value_a", SimpleValue(1));
+  user_model_.SetValue("value_b", SimpleValue(2));
+  EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+  EXPECT_EQ(user_model_.GetValue("result"), SimpleValue(true));
+
+  user_model_.SetValue("value_b", SimpleValue(1));
+  EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+  EXPECT_EQ(user_model_.GetValue("result"), SimpleValue(false));
 }
 
 TEST_F(BasicInteractionsTest, ComputeValueCreateCreditCardResponse) {
diff --git a/components/autofill_assistant/browser/element_area.cc b/components/autofill_assistant/browser/element_area.cc
index 6136a6e..0b513492 100644
--- a/components/autofill_assistant/browser/element_area.cc
+++ b/components/autofill_assistant/browser/element_area.cc
@@ -50,6 +50,9 @@
 
 void ElementArea::SetFromProto(const ElementAreaProto& proto) {
   rectangles_.clear();
+  last_visual_viewport_ = RectF();
+  last_rectangles_.clear();
+
   AddRectangles(proto.touchable(), /* restricted= */ false);
   AddRectangles(proto.restricted(), /* restricted= */ true);
 
diff --git a/components/autofill_assistant/browser/element_area_unittest.cc b/components/autofill_assistant/browser/element_area_unittest.cc
index 17b6f48..3ccde28 100644
--- a/components/autofill_assistant/browser/element_area_unittest.cc
+++ b/components/autofill_assistant/browser/element_area_unittest.cc
@@ -164,6 +164,17 @@
   EXPECT_THAT(reported_area_, ElementsAre(MatchingRectF(25, 25, 75, 75)));
 }
 
+TEST_F(ElementAreaTest, CallOnUpdateAfterSetFromProto) {
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementPosition(Eq(Selector({"#found"}).MustBeVisible()), _))
+      .WillRepeatedly(RunOnceCallback<1>(true, RectF(25, 25, 75, 75)));
+
+  SetElement("#found");
+  EXPECT_EQ(on_update_call_count_, 1);
+  SetElement("#found");
+  EXPECT_EQ(on_update_call_count_, 2);
+}
+
 TEST_F(ElementAreaTest, DontCallOnUpdateWhenViewportMissing) {
   // Swallowing calls to OnGetVisualViewport guarantees that the viewport
   // position will never be known.
diff --git a/components/autofill_assistant/browser/generic_ui.proto b/components/autofill_assistant/browser/generic_ui.proto
index e4031ba9..f27361b 100644
--- a/components/autofill_assistant/browser/generic_ui.proto
+++ b/components/autofill_assistant/browser/generic_ui.proto
@@ -208,9 +208,9 @@
   optional string locale = 2;
 }
 
-// A comparison of two values in the form |value_a| <mode> |value_b|. EQUAL is
-// supported for all values. All other comparison modes are only supported for
-// single integers, strings, and dates.
+// A comparison of two values in the form |value_a| <mode> |value_b|. EQUAL and
+// NOT_EQUAL are supported for all values. All other comparison modes are only
+// supported for single integers, strings, and dates.
 message ValueComparisonProto {
   enum Mode {
     UNDEFINED = 0;
@@ -219,6 +219,7 @@
     EQUAL = 3;
     GREATER_OR_EQUAL = 4;
     GREATER = 5;
+    NOT_EQUAL = 6;
   }
 
   // The first value to compare.
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 9f6c5cf..a94716e 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -1325,6 +1325,8 @@
     // The model containing the values for all keys specified in
     // |output_model_identifiers|.
     optional ModelProto model = 1;
+    // Set to true if the action was interrupted by a navigation event.
+    optional bool navigation_ended = 2;
   }
 
   // The generic user interface to show.
@@ -1357,6 +1359,12 @@
     repeated ElementCheck element_checks = 1;
   }
   optional PeriodicElementChecks periodic_element_checks = 6;
+  // When set to true, end this action on navigation events. The result will
+  // have |navigation_ended| set to true.
+  optional bool end_on_navigation = 7;
+  // If true, run scripts flagged with |interrupt=true| as soon as their
+  // preconditions match, then go back to the parent action.
+  optional bool allow_interrupt = 8;
 }
 
 // Allow choosing one or more possibility. If FocusElement was called just
diff --git a/components/blocklist/opt_out_blocklist/opt_out_blocklist.cc b/components/blocklist/opt_out_blocklist/opt_out_blocklist.cc
index 8a451845..0aa180d 100644
--- a/components/blocklist/opt_out_blocklist/opt_out_blocklist.cc
+++ b/components/blocklist/opt_out_blocklist/opt_out_blocklist.cc
@@ -168,6 +168,9 @@
   blocklist_data_->ClearData();
   loaded_ = false;
 
+  // Notify |blocklist_delegate_| on blocklist load status
+  blocklist_delegate_->OnLoadingStateChanged(loaded_);
+
   // Notify |blocklist_delegate_| that the blocklist is cleared.
   blocklist_delegate_->OnBlocklistCleared(clock_->Now());
 
@@ -216,6 +219,9 @@
     std::move(pending_callbacks_.front()).Run();
     pending_callbacks_.pop();
   }
+
+  // Notify |blocklist_delegate_| on blocklist load status
+  blocklist_delegate_->OnLoadingStateChanged(loaded_);
 }
 
 }  // namespace blocklist
diff --git a/components/blocklist/opt_out_blocklist/opt_out_blocklist_delegate.h b/components/blocklist/opt_out_blocklist/opt_out_blocklist_delegate.h
index 14b767a..ed899cad 100644
--- a/components/blocklist/opt_out_blocklist/opt_out_blocklist_delegate.h
+++ b/components/blocklist/opt_out_blocklist/opt_out_blocklist_delegate.h
@@ -27,11 +27,11 @@
 
   // Notifies |this| that the user blocklisted has changed, and it is
   // guaranteed to be called when the user blocklisted status is changed.
-  //
-  // TODO(crbug/1099030): Update the comment and interface to support providing
-  // a signal that the blocklist is loaded and available.
   virtual void OnUserBlocklistedStatusChange(bool blocklisted) {}
 
+  // Notifies |this| the blocklist loaded state changed to |is_loaded|.
+  virtual void OnLoadingStateChanged(bool is_load) {}
+
   // Notifies |this| that the blocklist is cleared at |time|.
   virtual void OnBlocklistCleared(base::Time time) {}
 };
diff --git a/components/blocklist/opt_out_blocklist/opt_out_blocklist_unittest.cc b/components/blocklist/opt_out_blocklist/opt_out_blocklist_unittest.cc
index a5d5cee..b2e1624 100644
--- a/components/blocklist/opt_out_blocklist/opt_out_blocklist_unittest.cc
+++ b/components/blocklist/opt_out_blocklist/opt_out_blocklist_unittest.cc
@@ -49,6 +49,9 @@
   void OnUserBlocklistedStatusChange(bool blocklisted) override {
     user_blocklisted_ = blocklisted;
   }
+  void OnLoadingStateChanged(bool is_loaded) override {
+    blocklist_loaded_ = is_loaded;
+  }
   void OnBlocklistCleared(base::Time time) override {
     blocklist_cleared_ = true;
     blocklist_cleared_time_ = time;
@@ -62,6 +65,9 @@
   // Gets the state of user blocklisted status.
   bool user_blocklisted() const { return user_blocklisted_; }
 
+  // Gets the load state of blocklist.
+  bool blocklist_loaded() const { return blocklist_loaded_; }
+
   // Gets the state of blocklisted cleared status of |this| for testing.
   bool blocklist_cleared() const { return blocklist_cleared_; }
 
@@ -72,6 +78,9 @@
   // The user blocklisted status of |this| blocklist_delegate.
   bool user_blocklisted_ = false;
 
+  // The blocklist load status of |this| blocklist_delegate.
+  bool blocklist_loaded_ = false;
+
   // Check if the blocklist is notified as cleared on |this| blocklist_delegate.
   bool blocklist_cleared_ = false;
 
@@ -952,6 +961,7 @@
   opt_out_store->SetBlocklistData(std::move(data));
 
   EXPECT_FALSE(blocklist_delegate_.user_blocklisted());
+  EXPECT_FALSE(blocklist_delegate_.blocklist_loaded());
   allowed_types.clear();
   allowed_types[1] = 0;
   auto block_list = std::make_unique<TestOptOutBlocklist>(
@@ -966,6 +976,7 @@
   block_list->Init();
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(blocklist_delegate_.user_blocklisted());
+  EXPECT_TRUE(blocklist_delegate_.blocklist_loaded());
 }
 
 TEST_F(OptOutBlocklistTest, ObserverIsNotifiedOfHistoricalBlocklistedHosts) {
diff --git a/components/client_hints/OWNERS b/components/client_hints/OWNERS
index 9f8f91b..8869c6b 100644
--- a/components/client_hints/OWNERS
+++ b/components/client_hints/OWNERS
@@ -1,5 +1,6 @@
 yoavweiss@chromium.org
 tbansal@chromium.org
 ryansturm@chromium.org
+aarontag@chromium.org
 
 # COMPONENT: Blink>Loader
diff --git a/components/management_strings.grdp b/components/management_strings.grdp
index 3d1fc30..021b1f6 100644
--- a/components/management_strings.grdp
+++ b/components/management_strings.grdp
@@ -126,7 +126,7 @@
       Websites you visit and the contents of not secure pages
     </message>
     <message name="IDS_MANAGEMENT_REPORT_PLUGIN_VM" desc="Message telling users that Plugin VM can collect data.">
-      <ph name="APP_NAME">$1<ex>Plugin VM</ex></ph> collects diagnostics data to improve the product experience. See <ph name="BEGIN_LINK">&lt;a target="_blank" href="https://www.parallels.com/pcep"&gt;</ph>https://www.parallels.com/pcep<ph name="END_LINK">&lt;/a&gt;</ph> for more information.
+      Your administrator has allowed <ph name="APP_NAME">$1<ex>Plugin VM</ex></ph> to collect diagnostics data to improve the product experience. See <ph name="BEGIN_LINK">&lt;a target="_blank" href="https://www.parallels.com/pcep"&gt;</ph>https://www.parallels.com/pcep<ph name="END_LINK">&lt;/a&gt;</ph> for more information.
     </message>
 
     <!-- Chrome OS update required end-of-life reached section -->
diff --git a/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_PLUGIN_VM.png.sha1 b/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_PLUGIN_VM.png.sha1
index ab12155c..a1504fe 100644
--- a/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_PLUGIN_VM.png.sha1
+++ b/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_PLUGIN_VM.png.sha1
@@ -1 +1 @@
-516d0e7dac1ff3fdf9bb21437fa124fb807cb147
\ No newline at end of file
+d2003f243a5af1b041f136b9d1bef898f1f14927
\ No newline at end of file
diff --git a/components/password_manager/core/browser/multi_store_form_fetcher.cc b/components/password_manager/core/browser/multi_store_form_fetcher.cc
index 1cb500b..960313b 100644
--- a/components/password_manager/core/browser/multi_store_form_fetcher.cc
+++ b/components/password_manager/core/browser/multi_store_form_fetcher.cc
@@ -116,7 +116,7 @@
   if (store.get() == client_->GetProfilePasswordStore() &&
       should_migrate_http_passwords_ && results.empty() &&
       form_digest_.url.SchemeIs(url::kHttpsScheme)) {
-    // TODO(crbug.com/1095556): Consider also supporting HTTP->HTTPS migration
+    // TODO(crbug.com/1107741): Consider also supporting HTTP->HTTPS migration
     // for the account store.
     http_migrator_ = std::make_unique<HttpPasswordStoreMigrator>(
         url::Origin::Create(form_digest_.url), client_, this);
diff --git a/components/password_manager/core/browser/password_manager_client_helper.cc b/components/password_manager/core/browser/password_manager_client_helper.cc
index 067d653..c6ff2da2 100644
--- a/components/password_manager/core/browser/password_manager_client_helper.cc
+++ b/components/password_manager/core/browser/password_manager_client_helper.cc
@@ -87,6 +87,8 @@
     const PasswordFormManagerForUI& submitted_manager) const {
   return delegate_->GetPasswordFeatureManager()
              ->ShouldShowAccountStorageBubbleUi() &&
+         delegate_->GetPasswordFeatureManager()->GetDefaultPasswordStore() ==
+             autofill::PasswordForm::Store::kAccountStore &&
          submitted_manager.IsMovableToAccountStore() &&
          !delegate_->IsIncognito();
 }
diff --git a/components/password_manager/core/browser/password_manager_client_helper_unittest.cc b/components/password_manager/core/browser/password_manager_client_helper_unittest.cc
index 79c7926d..affef187 100644
--- a/components/password_manager/core/browser/password_manager_client_helper_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_client_helper_unittest.cc
@@ -121,14 +121,33 @@
       CreateFormManager(&form, /*is_movable=*/true));
 }
 
-TEST_F(PasswordManagerClientHelperTest, PromptMoveForMovableForm) {
+TEST_F(PasswordManagerClientHelperTest, PromptMoveForMovableFormInAccountMode) {
   EXPECT_CALL(*client()->GetPasswordFeatureManager(),
               ShouldShowAccountStorageBubbleUi)
       .WillOnce(Return(true));
+  EXPECT_CALL(*client()->GetPasswordFeatureManager(), GetDefaultPasswordStore)
+      .WillOnce(Return(autofill::PasswordForm::Store::kAccountStore));
   EXPECT_CALL(*client(), PromptUserToMovePasswordToAccount);
   EXPECT_CALL(*client(), PromptUserToEnableAutosignin).Times(0);
 
-  // Indicate successful login without matching form.
+  // Indicate successful login.
+  const PasswordForm form =
+      CreateForm(kTestUsername, kTestPassword, GURL(kTestOrigin));
+  helper()->NotifySuccessfulLoginWithExistingPassword(
+      CreateFormManager(&form, /*is_movable=*/true));
+}
+
+TEST_F(PasswordManagerClientHelperTest,
+       NoPromptToMoveForMovableFormInProfileMode) {
+  EXPECT_CALL(*client()->GetPasswordFeatureManager(),
+              ShouldShowAccountStorageBubbleUi)
+      .WillOnce(Return(true));
+  EXPECT_CALL(*client()->GetPasswordFeatureManager(), GetDefaultPasswordStore)
+      .WillOnce(Return(autofill::PasswordForm::Store::kProfileStore));
+  EXPECT_CALL(*client(), PromptUserToMovePasswordToAccount).Times(0);
+  EXPECT_CALL(*client(), PromptUserToEnableAutosignin).Times(0);
+
+  // Indicate successful login.
   const PasswordForm form =
       CreateForm(kTestUsername, kTestPassword, GURL(kTestOrigin));
   helper()->NotifySuccessfulLoginWithExistingPassword(
diff --git a/components/password_manager/ios/password_form_helper.mm b/components/password_manager/ios/password_form_helper.mm
index 27781e0..c806e85 100644
--- a/components/password_manager/ios/password_form_helper.mm
+++ b/components/password_manager/ios/password_form_helper.mm
@@ -14,12 +14,10 @@
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/password_form_fill_data.h"
 #include "components/autofill/ios/browser/autofill_util.h"
-#include "components/password_manager/core/browser/password_form_filling.h"
 #include "components/password_manager/ios/account_select_fill_data.h"
 #include "components/password_manager/ios/js_password_manager.h"
 #import "ios/web/public/js_messaging/web_frame.h"
 #import "ios/web/public/js_messaging/web_frame_util.h"
-#import "ios/web/public/js_messaging/web_frames_manager.h"
 #import "ios/web/public/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -32,6 +30,7 @@
 using autofill::FieldRendererId;
 using autofill::PasswordFormFillData;
 using base::SysNSStringToUTF16;
+using base::SysUTF16ToNSString;
 using password_manager::FillData;
 using password_manager::GetPageURLAndCheckTrustLevel;
 using password_manager::SerializePasswordFormFillData;
@@ -68,14 +67,6 @@
                          pageURL:(const GURL&)pageURL
                            forms:(std::vector<FormData>*)forms;
 
-// Autofills |username| and |password| into the form specified by |formData|,
-// invoking |completionHandler| when finished with YES if successful and
-// NO otherwise. |completionHandler| may be nil.
-- (void)fillPasswordForm:(const autofill::PasswordFormFillData&)formData
-            withUsername:(const base::string16&)username
-                password:(const base::string16&)password
-       completionHandler:(nullable void (^)(BOOL))completionHandler;
-
 @end
 
 // Category for test only.
@@ -247,47 +238,6 @@
   *forms = std::move(formsData);
 }
 
-// TODO(kazinova): remove unnecessary arguments.
-- (void)fillPasswordForm:(const autofill::PasswordFormFillData&)formData
-            withUsername:(const base::string16&)username
-                password:(const base::string16&)password
-       completionHandler:(nullable void (^)(BOOL))completionHandler {
-  if (formData.url.GetOrigin() != self.lastCommittedURL.GetOrigin()) {
-    if (completionHandler) {
-      completionHandler(NO);
-    }
-    return;
-  }
-
-  // Necessary copy so the values can be used inside a block.
-  FieldRendererId usernameID = formData.username_field.unique_renderer_id;
-  FieldRendererId passwordID = formData.password_field.unique_renderer_id;
-  base::string16 usernameValue = username;
-  base::string16 passwordValue = password;
-
-  // Send JSON over to the web view.
-  __weak PasswordFormHelper* weakSelf = self;
-  [self.jsPasswordManager
-       fillPasswordForm:SerializePasswordFormFillData(formData)
-                inFrame:GetMainFrame(_webState)
-           withUsername:base::SysUTF16ToNSString(username)
-               password:base::SysUTF16ToNSString(password)
-      completionHandler:^(NSString* result) {
-        BOOL success = [result isEqual:@"true"];
-        if (success) {
-          weakSelf.fieldDataManager->UpdateFieldDataWithAutofilledValue(
-              usernameID, usernameValue,
-              FieldPropertiesFlags::kAutofilledOnPageLoad);
-          weakSelf.fieldDataManager->UpdateFieldDataWithAutofilledValue(
-              passwordID, passwordValue,
-              FieldPropertiesFlags::kAutofilledOnPageLoad);
-        }
-        if (completionHandler) {
-          completionHandler(success);
-        }
-      }];
-}
-
 // Extracts known field data.
 - (void)extractKnownFieldData:(FormData&)form {
   for (auto& field : form.fields) {
@@ -343,29 +293,47 @@
 
 - (void)fillPasswordForm:(const autofill::PasswordFormFillData&)formData
        completionHandler:(nullable void (^)(BOOL))completionHandler {
-  // Don't fill immediately if waiting for the user to type a username.
-  if (formData.wait_for_username) {
+  // Necessary copy so the values can be used inside a block.
+  FieldRendererId usernameID = formData.username_field.unique_renderer_id;
+  FieldRendererId passwordID = formData.password_field.unique_renderer_id;
+  base::string16 usernameValue = formData.username_field.value;
+  base::string16 passwordValue = formData.password_field.value;
+
+  // Don't fill if:
+  // 1. Waiting for the user to type a username.
+  // 2. |formData|'s origin is not matching the origin of the last commited URL.
+  // 3. If a field has user typed input or input filled on user trigger.
+  if (formData.wait_for_username ||
+      formData.url.GetOrigin() != self.lastCommittedURL.GetOrigin() ||
+      self.fieldDataManager->WasAutofilledOnUserTrigger(passwordID) ||
+      self.fieldDataManager->DidUserType(passwordID)) {
     if (completionHandler) {
       completionHandler(NO);
     }
     return;
   }
 
-  // Do not refill the form if a field has user typed input or input filled
-  // on user trigger.
-  FieldRendererId passwordId = formData.password_field.unique_renderer_id;
-  if (self.fieldDataManager->WasAutofilledOnUserTrigger(passwordId) ||
-      self.fieldDataManager->DidUserType(passwordId)) {
-    if (completionHandler) {
-      completionHandler(NO);
-    }
-    return;
-  }
-
-  [self fillPasswordForm:formData
-            withUsername:formData.username_field.value
-                password:formData.password_field.value
-       completionHandler:completionHandler];
+  // Send JSON over to the web view.
+  __weak PasswordFormHelper* weakSelf = self;
+  [self.jsPasswordManager
+       fillPasswordForm:SerializePasswordFormFillData(formData)
+                inFrame:GetMainFrame(_webState)
+           withUsername:SysUTF16ToNSString(formData.username_field.value)
+               password:SysUTF16ToNSString(formData.password_field.value)
+      completionHandler:^(NSString* result) {
+        BOOL success = [result isEqual:@"true"];
+        if (success) {
+          weakSelf.fieldDataManager->UpdateFieldDataWithAutofilledValue(
+              usernameID, usernameValue,
+              FieldPropertiesFlags::kAutofilledOnPageLoad);
+          weakSelf.fieldDataManager->UpdateFieldDataWithAutofilledValue(
+              passwordID, passwordValue,
+              FieldPropertiesFlags::kAutofilledOnPageLoad);
+        }
+        if (completionHandler) {
+          completionHandler(success);
+        }
+      }];
 }
 
 - (void)fillPasswordForm:(FormRendererId)formIdentifier
@@ -412,8 +380,8 @@
   [self.jsPasswordManager
        fillPasswordForm:SerializeFillData(fillData)
                 inFrame:GetMainFrame(_webState)
-           withUsername:base::SysUTF16ToNSString(usernameValue)
-               password:base::SysUTF16ToNSString(passwordValue)
+           withUsername:SysUTF16ToNSString(usernameValue)
+               password:SysUTF16ToNSString(passwordValue)
       completionHandler:^(NSString* result) {
         BOOL success = [result isEqual:@"true"];
         if (success) {
diff --git a/components/prefs/android/BUILD.gn b/components/prefs/android/BUILD.gn
index fccae3c..2aa2728d 100644
--- a/components/prefs/android/BUILD.gn
+++ b/components/prefs/android/BUILD.gn
@@ -17,20 +17,3 @@
   ]
   annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
 }
-
-java_library("junit") {
-  # Skip platform checks since Robolectric depends on requires_android targets.
-  bypass_platform_checks = true
-  testonly = true
-  sources = [ "java/src/org/chromium/components/prefs/PrefServiceTest.java" ]
-  deps = [
-    ":java",
-    "//base:base_java",
-    "//base:base_java_test_support",
-    "//base:base_junit_test_support",
-    "//base/test:test_support_java",
-    "//third_party/android_deps:robolectric_all_java",
-    "//third_party/junit",
-    "//third_party/mockito:mockito_java",
-  ]
-}
diff --git a/components/prefs/android/OWNERS b/components/prefs/android/OWNERS
deleted file mode 100644
index 3d0f7a5..0000000
--- a/components/prefs/android/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-twellington@chromium.org
-chouinard@chromium.org
-
-# COMPONENT: Internals>Preferences
-# OS: Android
diff --git a/components/prefs/android/java/src/org/chromium/components/prefs/PrefService.java b/components/prefs/android/java/src/org/chromium/components/prefs/PrefService.java
index 3ee3f8b..64f1d05b 100644
--- a/components/prefs/android/java/src/org/chromium/components/prefs/PrefService.java
+++ b/components/prefs/android/java/src/org/chromium/components/prefs/PrefService.java
@@ -5,7 +5,6 @@
 package org.chromium.components.prefs;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
@@ -24,8 +23,7 @@
         mNativePrefServiceAndroid = 0;
     }
 
-    @VisibleForTesting
-    PrefService(long nativePrefServiceAndroid) {
+    private PrefService(long nativePrefServiceAndroid) {
         mNativePrefServiceAndroid = nativePrefServiceAndroid;
     }
 
diff --git a/components/prefs/android/java/src/org/chromium/components/prefs/PrefServiceTest.java b/components/prefs/android/java/src/org/chromium/components/prefs/PrefServiceTest.java
deleted file mode 100644
index e1de428a..0000000
--- a/components/prefs/android/java/src/org/chromium/components/prefs/PrefServiceTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// generate_java_test.py
-
-package org.chromium.components.prefs;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.verify;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
-
-import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.base.test.util.JniMocker;
-
-/** Unit tests for {@link PrefService}. */
-@RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-public class PrefServiceTest {
-    private static final String PREF = "42";
-    private static final long NATIVE_HANDLE = 117;
-
-    @Rule
-    public JniMocker mocker = new JniMocker();
-    @Mock
-    private PrefService.Natives mNativeMock;
-
-    PrefService mPrefService;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mocker.mock(PrefServiceJni.TEST_HOOKS, mNativeMock);
-        mPrefService = new PrefService(NATIVE_HANDLE);
-    }
-
-    @Test
-    public void testGetBoolean() {
-        boolean expected = false;
-
-        doReturn(expected).when(mNativeMock).getBoolean(NATIVE_HANDLE, PREF);
-
-        assertEquals(expected, mPrefService.getBoolean(PREF));
-    }
-
-    @Test
-    public void testSetBoolean() {
-        boolean value = true;
-
-        mPrefService.setBoolean(PREF, value);
-
-        verify(mNativeMock).setBoolean(eq(NATIVE_HANDLE), eq(PREF), eq(value));
-    }
-
-    @Test
-    public void testGetInteger() {
-        int expected = 26;
-
-        doReturn(expected).when(mNativeMock).getInteger(NATIVE_HANDLE, PREF);
-
-        assertEquals(expected, mPrefService.getInteger(PREF));
-    }
-
-    @Test
-    public void testSetInteger() {
-        int value = 62;
-
-        mPrefService.setInteger(PREF, value);
-
-        verify(mNativeMock).setInteger(eq(NATIVE_HANDLE), eq(PREF), eq(value));
-    }
-
-    @Test
-    public void testGetString() {
-        String expected = "foo";
-
-        doReturn(expected).when(mNativeMock).getString(NATIVE_HANDLE, PREF);
-
-        assertEquals(expected, mPrefService.getString(PREF));
-    }
-
-    @Test
-    public void testSetString() {
-        String value = "bar";
-
-        mPrefService.setString(PREF, value);
-
-        verify(mNativeMock).setString(eq(NATIVE_HANDLE), eq(PREF), eq(value));
-    }
-
-    @Test
-    public void testIsManaged() {
-        boolean expected = true;
-
-        doReturn(expected).when(mNativeMock).isManagedPreference(NATIVE_HANDLE, PREF);
-
-        assertEquals(expected, mPrefService.isManagedPreference(PREF));
-    }
-}
diff --git a/components/prerender/common/BUILD.gn b/components/prerender/common/BUILD.gn
index b5cd57e..8434b65 100644
--- a/components/prerender/common/BUILD.gn
+++ b/components/prerender/common/BUILD.gn
@@ -10,11 +10,14 @@
     "prerender_final_status.h",
     "prerender_origin.cc",
     "prerender_origin.h",
+    "prerender_url_loader_throttle.cc",
+    "prerender_url_loader_throttle.h",
     "prerender_util.cc",
     "prerender_util.h",
   ]
   deps = [
     ":mojo_bindings",
+    "//content/public/common:common",
     "//extensions/common:common_constants",
     "//ipc",
     "//ipc:message_support",
diff --git a/chrome/common/prerender_url_loader_throttle.cc b/components/prerender/common/prerender_url_loader_throttle.cc
similarity index 98%
rename from chrome/common/prerender_url_loader_throttle.cc
rename to components/prerender/common/prerender_url_loader_throttle.cc
index c3ecc81..d3bf2e04 100644
--- a/chrome/common/prerender_url_loader_throttle.cc
+++ b/components/prerender/common/prerender_url_loader_throttle.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/common/prerender_url_loader_throttle.h"
+#include "components/prerender/common/prerender_url_loader_throttle.h"
 
 #include "base/bind.h"
 #include "build/build_config.h"
diff --git a/chrome/common/prerender_url_loader_throttle.h b/components/prerender/common/prerender_url_loader_throttle.h
similarity index 92%
rename from chrome/common/prerender_url_loader_throttle.h
rename to components/prerender/common/prerender_url_loader_throttle.h
index f7b35f5..ad5ef19 100644
--- a/chrome/common/prerender_url_loader_throttle.h
+++ b/components/prerender/common/prerender_url_loader_throttle.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
-#define CHROME_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
+#ifndef COMPONENTS_PRERENDER_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
+#define COMPONENTS_PRERENDER_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
 
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
@@ -75,4 +75,4 @@
 
 }  // namespace prerender
 
-#endif  // CHROME_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
+#endif  // COMPONENTS_PRERENDER_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
diff --git a/components/prerender/renderer/BUILD.gn b/components/prerender/renderer/BUILD.gn
new file mode 100644
index 0000000..4a20615b
--- /dev/null
+++ b/components/prerender/renderer/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+static_library("renderer") {
+  sources = [
+    "prerender_helper.cc",
+    "prerender_helper.h",
+  ]
+
+  deps = [
+    "//components/prerender/common",
+    "//components/prerender/common:mojo_bindings",
+    "//content/public/renderer",
+    "//third_party/blink/public:blink_headers",
+  ]
+}
diff --git a/components/prerender/renderer/DEPS b/components/prerender/renderer/DEPS
new file mode 100644
index 0000000..dec58a9b
--- /dev/null
+++ b/components/prerender/renderer/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+content/public/renderer",
+  "+third_party/blink/public",
+]
diff --git a/chrome/renderer/prerender/prerender_helper.cc b/components/prerender/renderer/prerender_helper.cc
similarity index 97%
rename from chrome/renderer/prerender/prerender_helper.cc
rename to components/prerender/renderer/prerender_helper.cc
index e1e6912..820b305 100644
--- a/chrome/renderer/prerender/prerender_helper.cc
+++ b/components/prerender/renderer/prerender_helper.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/renderer/prerender/prerender_helper.h"
+#include "components/prerender/renderer/prerender_helper.h"
 
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
-#include "chrome/common/prerender_url_loader_throttle.h"
+#include "components/prerender//common/prerender_url_loader_throttle.h"
 #include "content/public/renderer/document_state.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_thread.h"
diff --git a/chrome/renderer/prerender/prerender_helper.h b/components/prerender/renderer/prerender_helper.h
similarity index 93%
rename from chrome/renderer/prerender/prerender_helper.h
rename to components/prerender/renderer/prerender_helper.h
index 492bf98..7187e74 100644
--- a/chrome/renderer/prerender/prerender_helper.h
+++ b/components/prerender/renderer/prerender_helper.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_RENDERER_PRERENDER_PRERENDER_HELPER_H_
-#define CHROME_RENDERER_PRERENDER_PRERENDER_HELPER_H_
+#ifndef COMPONENTS_PRERENDER_RENDERER_PRERENDER_HELPER_H_
+#define COMPONENTS_PRERENDER_RENDERER_PRERENDER_HELPER_H_
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
@@ -78,4 +78,4 @@
 
 }  // namespace prerender
 
-#endif  // CHROME_RENDERER_PRERENDER_PRERENDER_HELPER_H_
+#endif  // COMPONENTS_PRERENDER_RENDERER_PRERENDER_HELPER_H_
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index 634cbe9e..446950f 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -853,12 +853,17 @@
 SkiaOutputSurfaceImplOnGpu::~SkiaOutputSurfaceImplOnGpu() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  // |context_provider_| and clients want either the context to be lost or made
-  // current on destruction.
-  if (context_state_ && MakeCurrent(false /* need_fbo0 */)) {
-    // This ensures any outstanding callbacks for promise images are performed.
-    gr_context()->flushAndSubmit();
-    release_current_last_.emplace(gl_surface_, context_state_);
+  if (context_state_) {
+    context_state_->RemoveContextLostObserver(this);
+
+    // |context_provider_| and clients want either the context to be lost or
+    // made current on destruction.
+    if (MakeCurrent(false /* need_fbo0 */)) {
+      // This ensures any outstanding callbacks for promise images are
+      // performed.
+      gr_context()->flushAndSubmit();
+      release_current_last_.emplace(gl_surface_, context_state_);
+    }
   }
 
   if (copier_) {
@@ -1478,6 +1483,9 @@
                             !features::IsUsingSkiaForGLReadback();
   max_resource_cache_bytes_ =
       context_state_->gr_context()->getResourceCacheLimit();
+  if (context_state_)
+    context_state_->AddContextLostObserver(this);
+
   return true;
 }
 
@@ -1827,6 +1835,10 @@
       &SkiaOutputSurfaceImplOnGpu::DidSwapBuffersCompleteInternal, weak_ptr_);
 }
 
+void SkiaOutputSurfaceImplOnGpu::OnContextLost() {
+  MarkContextLost(ContextLostReason::CONTEXT_LOST_UNKNOWN);
+}
+
 void SkiaOutputSurfaceImplOnGpu::MarkContextLost(ContextLostReason reason) {
   // This function potentially can be re-entered during from
   // SharedContextState::MarkContextLost(). This guards against it.
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
index 554539b..9140522 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -70,7 +70,9 @@
 
 // The SkiaOutputSurface implementation running on the GPU thread. This class
 // should be created, used and destroyed on the GPU thread.
-class SkiaOutputSurfaceImplOnGpu : public gpu::ImageTransportSurfaceDelegate {
+class SkiaOutputSurfaceImplOnGpu
+    : public gpu::ImageTransportSurfaceDelegate,
+      public gpu::SharedContextState::ContextLostObserver {
  public:
   class ScopedUseContextProvider;
 
@@ -186,6 +188,9 @@
 
   bool IsDisplayedAsOverlay();
 
+  // gpu::SharedContextState::ContextLostObserver implementation:
+  void OnContextLost() override;
+
   // gpu::ImageTransportSurfaceDelegate implementation:
 #if defined(OS_WIN)
   void DidCreateAcceleratedSurfaceChildWindow(
diff --git a/content/browser/accessibility/accessibility_tree_formatter_blink.cc b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
index ce2b041..bec5d29 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_blink.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
@@ -96,7 +96,7 @@
     case ax::mojom::IntAttribute::kTextUnderlineStyle:
       return ui::ToString(static_cast<ax::mojom::TextDecorationStyle>(value));
     case ax::mojom::IntAttribute::kTextDirection:
-      return ui::ToString(static_cast<ax::mojom::TextDirection>(value));
+      return ui::ToString(static_cast<ax::mojom::WritingDirection>(value));
     case ax::mojom::IntAttribute::kTextPosition:
       return ui::ToString(static_cast<ax::mojom::TextPosition>(value));
     case ax::mojom::IntAttribute::kImageAnnotationStatus:
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 64f0b04..764dff8 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -660,25 +660,25 @@
   }
 
   // Step 2: correct for the thickness of the caret.
-  auto text_direction = static_cast<ax::mojom::TextDirection>(
+  auto text_direction = static_cast<ax::mojom::WritingDirection>(
       GetIntAttribute(ax::mojom::IntAttribute::kTextDirection));
   constexpr int kCaretThickness = 1;
   switch (text_direction) {
-    case ax::mojom::TextDirection::kNone:
-    case ax::mojom::TextDirection::kLtr: {
+    case ax::mojom::WritingDirection::kNone:
+    case ax::mojom::WritingDirection::kLtr: {
       bounds.set_width(kCaretThickness);
       break;
     }
-    case ax::mojom::TextDirection::kRtl: {
+    case ax::mojom::WritingDirection::kRtl: {
       bounds.set_x(bounds.right() - kCaretThickness);
       bounds.set_width(kCaretThickness);
       break;
     }
-    case ax::mojom::TextDirection::kTtb: {
+    case ax::mojom::WritingDirection::kTtb: {
       bounds.set_height(kCaretThickness);
       break;
     }
-    case ax::mojom::TextDirection::kBtt: {
+    case ax::mojom::WritingDirection::kBtt: {
       bounds.set_y(bounds.bottom() - kCaretThickness);
       bounds.set_height(kCaretThickness);
       break;
@@ -787,25 +787,25 @@
   const int location_height = location.height();
 
   gfx::RectF bounds;
-  switch (static_cast<ax::mojom::TextDirection>(
+  switch (static_cast<ax::mojom::WritingDirection>(
       GetIntAttribute(ax::mojom::IntAttribute::kTextDirection))) {
-    case ax::mojom::TextDirection::kNone:
-    case ax::mojom::TextDirection::kLtr:
+    case ax::mojom::WritingDirection::kNone:
+    case ax::mojom::WritingDirection::kLtr:
       bounds =
           gfx::RectF(start_pixel_offset, 0,
                      end_pixel_offset - start_pixel_offset, location_height);
       break;
-    case ax::mojom::TextDirection::kRtl: {
+    case ax::mojom::WritingDirection::kRtl: {
       const int left = max_pixel_offset - end_pixel_offset;
       const int right = max_pixel_offset - start_pixel_offset;
       bounds = gfx::RectF(left, 0, right - left, location_height);
       break;
     }
-    case ax::mojom::TextDirection::kTtb:
+    case ax::mojom::WritingDirection::kTtb:
       bounds = gfx::RectF(0, start_pixel_offset, location_width,
                           end_pixel_offset - start_pixel_offset);
       break;
-    case ax::mojom::TextDirection::kBtt: {
+    case ax::mojom::WritingDirection::kBtt: {
       const int top = max_pixel_offset - end_pixel_offset;
       const int bottom = max_pixel_offset - start_pixel_offset;
       bounds = gfx::RectF(0, top, location_width, bottom - top);
diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
index 971f451..de5fb71 100644
--- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
@@ -136,7 +136,7 @@
   inline_text1.role = ax::mojom::Role::kInlineTextBox;
   inline_text1.SetName("Hello, ");
   inline_text1.relative_bounds.bounds = gfx::RectF(100, 100, 29, 9);
-  inline_text1.SetTextDirection(ax::mojom::TextDirection::kLtr);
+  inline_text1.SetTextDirection(ax::mojom::WritingDirection::kLtr);
   std::vector<int32_t> character_offsets1;
   character_offsets1.push_back(6);   // 0
   character_offsets1.push_back(11);  // 1
@@ -154,7 +154,7 @@
   inline_text2.role = ax::mojom::Role::kInlineTextBox;
   inline_text2.SetName("world.");
   inline_text2.relative_bounds.bounds = gfx::RectF(100, 109, 28, 9);
-  inline_text2.SetTextDirection(ax::mojom::TextDirection::kLtr);
+  inline_text2.SetTextDirection(ax::mojom::WritingDirection::kLtr);
   std::vector<int32_t> character_offsets2;
   character_offsets2.push_back(5);
   character_offsets2.push_back(10);
@@ -242,7 +242,7 @@
   inline_text1.role = ax::mojom::Role::kInlineTextBox;
   inline_text1.SetName("ABC");
   inline_text1.relative_bounds.bounds = gfx::RectF(0, 20, 33, 9);
-  inline_text1.SetTextDirection(ax::mojom::TextDirection::kLtr);
+  inline_text1.SetTextDirection(ax::mojom::WritingDirection::kLtr);
   std::vector<int32_t> character_offsets{10, 21, 33};
   inline_text1.AddIntListAttribute(
       ax::mojom::IntListAttribute::kCharacterOffsets, character_offsets);
@@ -260,7 +260,7 @@
   inline_text2.role = ax::mojom::Role::kInlineTextBox;
   inline_text2.SetName("ABC");
   inline_text2.relative_bounds.bounds = gfx::RectF(10, 40, 33, 9);
-  inline_text2.SetTextDirection(ax::mojom::TextDirection::kLtr);
+  inline_text2.SetTextDirection(ax::mojom::WritingDirection::kLtr);
   inline_text2.AddIntListAttribute(
       ax::mojom::IntListAttribute::kCharacterOffsets, character_offsets);
   static_text2.child_ids.push_back(5);
@@ -360,7 +360,7 @@
   inline_text1.role = ax::mojom::Role::kInlineTextBox;
   inline_text1.SetName("123");
   inline_text1.relative_bounds.bounds = gfx::RectF(100, 100, 30, 20);
-  inline_text1.SetTextDirection(ax::mojom::TextDirection::kLtr);
+  inline_text1.SetTextDirection(ax::mojom::WritingDirection::kLtr);
   std::vector<int32_t> character_offsets1;
   character_offsets1.push_back(10);  // 0
   character_offsets1.push_back(20);  // 1
@@ -374,7 +374,7 @@
   inline_text2.role = ax::mojom::Role::kInlineTextBox;
   inline_text2.SetName("abc");
   inline_text2.relative_bounds.bounds = gfx::RectF(130, 100, 30, 20);
-  inline_text2.SetTextDirection(ax::mojom::TextDirection::kRtl);
+  inline_text2.SetTextDirection(ax::mojom::WritingDirection::kRtl);
   std::vector<int32_t> character_offsets2;
   character_offsets2.push_back(10);
   character_offsets2.push_back(20);
@@ -457,7 +457,7 @@
   inline_text.role = ax::mojom::Role::kInlineTextBox;
   inline_text.SetName("ABC");
   inline_text.relative_bounds.bounds = gfx::RectF(100, 100, 16, 9);
-  inline_text.SetTextDirection(ax::mojom::TextDirection::kLtr);
+  inline_text.SetTextDirection(ax::mojom::WritingDirection::kLtr);
   std::vector<int32_t> character_offsets1;
   character_offsets1.push_back(6);   // 0
   character_offsets1.push_back(11);  // 1
@@ -536,7 +536,7 @@
   inline_text1.role = ax::mojom::Role::kInlineTextBox;
   inline_text1.SetName("AB");
   inline_text1.relative_bounds.bounds = gfx::RectF(100, 100, 40, 20);
-  inline_text1.SetTextDirection(ax::mojom::TextDirection::kLtr);
+  inline_text1.SetTextDirection(ax::mojom::WritingDirection::kLtr);
   std::vector<int32_t> character_offsets1;
   character_offsets1.push_back(20);  // 0
   character_offsets1.push_back(40);  // 1
@@ -548,7 +548,7 @@
   inline_text2.role = ax::mojom::Role::kInlineTextBox;
   inline_text2.SetName("CD");
   inline_text2.relative_bounds.bounds = gfx::RectF(160, 100, 40, 20);
-  inline_text2.SetTextDirection(ax::mojom::TextDirection::kLtr);
+  inline_text2.SetTextDirection(ax::mojom::WritingDirection::kLtr);
   std::vector<int32_t> character_offsets2;
   character_offsets2.push_back(20);  // 0
   character_offsets2.push_back(40);  // 1
diff --git a/content/browser/accessibility/browser_accessibility_unittest.cc b/content/browser/accessibility/browser_accessibility_unittest.cc
index ed559c391..c4800985 100644
--- a/content/browser/accessibility/browser_accessibility_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_unittest.cc
@@ -289,7 +289,7 @@
   inline_text1.role = ax::mojom::Role::kInlineTextBox;
   inline_text1.SetName("Hello, ");
   inline_text1.relative_bounds.bounds = gfx::RectF(100, 100, 29, 9);
-  inline_text1.SetTextDirection(ax::mojom::TextDirection::kLtr);
+  inline_text1.SetTextDirection(ax::mojom::WritingDirection::kLtr);
   std::vector<int32_t> character_offsets1;
   character_offsets1.push_back(6);
   character_offsets1.push_back(11);
@@ -307,7 +307,7 @@
   inline_text2.role = ax::mojom::Role::kInlineTextBox;
   inline_text2.SetName("world.");
   inline_text2.relative_bounds.bounds = gfx::RectF(100, 109, 28, 9);
-  inline_text2.SetTextDirection(ax::mojom::TextDirection::kLtr);
+  inline_text2.SetTextDirection(ax::mojom::WritingDirection::kLtr);
   std::vector<int32_t> character_offsets2;
   character_offsets2.push_back(5);
   character_offsets2.push_back(10);
@@ -410,7 +410,7 @@
   inline_text1.role = ax::mojom::Role::kInlineTextBox;
   inline_text1.SetName("ABC");
   inline_text1.relative_bounds.bounds = gfx::RectF(0, 20, 33, 9);
-  inline_text1.SetTextDirection(ax::mojom::TextDirection::kLtr);
+  inline_text1.SetTextDirection(ax::mojom::WritingDirection::kLtr);
   std::vector<int32_t> character_offsets{10, 21, 33};
   inline_text1.AddIntListAttribute(
       ax::mojom::IntListAttribute::kCharacterOffsets, character_offsets);
@@ -428,7 +428,7 @@
   inline_text2.role = ax::mojom::Role::kInlineTextBox;
   inline_text2.SetName("ABC");
   inline_text2.relative_bounds.bounds = gfx::RectF(10, 40, 33, 9);
-  inline_text2.SetTextDirection(ax::mojom::TextDirection::kLtr);
+  inline_text2.SetTextDirection(ax::mojom::WritingDirection::kLtr);
   inline_text2.AddIntListAttribute(
       ax::mojom::IntListAttribute::kCharacterOffsets, character_offsets);
   static_text2.child_ids.push_back(5);
@@ -537,7 +537,7 @@
   inline_text1.role = ax::mojom::Role::kInlineTextBox;
   inline_text1.SetName("123");
   inline_text1.relative_bounds.bounds = gfx::RectF(100, 100, 30, 20);
-  inline_text1.SetTextDirection(ax::mojom::TextDirection::kLtr);
+  inline_text1.SetTextDirection(ax::mojom::WritingDirection::kLtr);
   std::vector<int32_t> character_offsets1;
   character_offsets1.push_back(10);  // 0
   character_offsets1.push_back(20);  // 1
@@ -551,7 +551,7 @@
   inline_text2.role = ax::mojom::Role::kInlineTextBox;
   inline_text2.SetName("abc");
   inline_text2.relative_bounds.bounds = gfx::RectF(130, 100, 30, 20);
-  inline_text2.SetTextDirection(ax::mojom::TextDirection::kRtl);
+  inline_text2.SetTextDirection(ax::mojom::WritingDirection::kRtl);
   std::vector<int32_t> character_offsets2;
   character_offsets2.push_back(10);
   character_offsets2.push_back(20);
@@ -637,7 +637,7 @@
   inline_text.role = ax::mojom::Role::kInlineTextBox;
   inline_text.SetName("ABC");
   inline_text.relative_bounds.bounds = gfx::RectF(100, 100, 16, 9);
-  inline_text.SetTextDirection(ax::mojom::TextDirection::kLtr);
+  inline_text.SetTextDirection(ax::mojom::WritingDirection::kLtr);
   std::vector<int32_t> character_offsets1;
   character_offsets1.push_back(6);   // 0
   character_offsets1.push_back(11);  // 1
diff --git a/content/browser/appcache/appcache_backfillers.cc b/content/browser/appcache/appcache_backfillers.cc
index c6a6b9d9..f3509a30e 100644
--- a/content/browser/appcache/appcache_backfillers.cc
+++ b/content/browser/appcache/appcache_backfillers.cc
@@ -5,6 +5,7 @@
 #include "content/browser/appcache/appcache_backfillers.h"
 
 #include "content/browser/appcache/appcache_update_job.h"
+#include "net/http/http_request_headers.h"
 #include "sql/statement.h"
 #include "storage/browser/quota/padding_key.h"
 #include "url/gurl.h"
@@ -19,7 +20,7 @@
     return 0;
   return storage::ComputeResponsePadding(
       response_url, storage::GetDefaultPaddingKey(), /*has_metadata=*/false,
-      /*loaded_with_credentials=*/false);
+      /*loaded_with_credentials=*/false, net::HttpRequestHeaders::kGetMethod);
 }
 
 // Iterates over each Cache record; execute |callable| on each iteration.
diff --git a/content/browser/appcache/appcache_update_job.cc b/content/browser/appcache/appcache_update_job.cc
index 0680e53..a021817 100644
--- a/content/browser/appcache/appcache_update_job.cc
+++ b/content/browser/appcache/appcache_update_job.cc
@@ -26,6 +26,7 @@
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
 #include "net/base/request_priority.h"
+#include "net/http/http_request_headers.h"
 #include "storage/browser/quota/padding_key.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
@@ -196,10 +197,10 @@
   if (response_url.GetOrigin() == manifest_url.GetOrigin())
     return 0;
 
-  return storage::ComputeResponsePadding(response_url.spec(),
-                                         storage::GetDefaultPaddingKey(),
-                                         /*has_metadata=*/false,
-                                         /*loaded_with_credentials=*/false);
+  return storage::ComputeResponsePadding(
+      response_url.spec(), storage::GetDefaultPaddingKey(),
+      /*has_metadata=*/false, /*loaded_with_credentials=*/false,
+      net::HttpRequestHeaders::kGetMethod);
 }
 
 }  // namespace
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index a8ed8a5..a8913e6 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -43,8 +43,6 @@
 #include "content/browser/worker_host/shared_worker_host.h"
 #include "content/browser/xr/service/vr_service_impl.h"
 #include "content/common/input/input_injector.mojom.h"
-#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
-#include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/device_service.h"
@@ -92,6 +90,8 @@
 #include "third_party/blink/public/mojom/loader/content_security_notifier.mojom.h"
 #include "third_party/blink/public/mojom/loader/navigation_predictor.mojom.h"
 #include "third_party/blink/public/mojom/locks/lock_manager.mojom.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_output_stream_factory.mojom.h"
 #include "third_party/blink/public/mojom/mediasession/media_session.mojom.h"
 #include "third_party/blink/public/mojom/mediastream/media_devices.mojom.h"
 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
@@ -635,11 +635,11 @@
         GetIOThreadTaskRunner({}));
   }
 
-  map->Add<mojom::RendererAudioInputStreamFactory>(
+  map->Add<blink::mojom::RendererAudioInputStreamFactory>(
       base::BindRepeating(&RenderFrameHostImpl::CreateAudioInputStreamFactory,
                           base::Unretained(host)));
 
-  map->Add<mojom::RendererAudioOutputStreamFactory>(
+  map->Add<blink::mojom::RendererAudioOutputStreamFactory>(
       base::BindRepeating(&RenderFrameHostImpl::CreateAudioOutputStreamFactory,
                           base::Unretained(host)));
 
diff --git a/content/browser/cache_storage/cache_storage.proto b/content/browser/cache_storage/cache_storage.proto
index 3fcaef2..14ad0f0 100644
--- a/content/browser/cache_storage/cache_storage.proto
+++ b/content/browser/cache_storage/cache_storage.proto
@@ -55,6 +55,7 @@
   optional string alpn_negotiated_protocol = 11;
   optional bool was_fetched_via_spdy = 12;
   optional string mime_type = 13;
+  optional string request_method = 14;
 }
 
 message CacheMetadata {
diff --git a/content/browser/cache_storage/cache_storage_cache_unittest.cc b/content/browser/cache_storage/cache_storage_cache_unittest.cc
index 9395f795..8abdcef6 100644
--- a/content/browser/cache_storage/cache_storage_cache_unittest.cc
+++ b/content/browser/cache_storage/cache_storage_cache_unittest.cc
@@ -663,9 +663,9 @@
         network::mojom::FetchResponseSource::kUnspecified,
         base::flat_map<std::string, std::string>(kHeaders.cbegin(),
                                                  kHeaders.cend()),
-        base::nullopt /* mime_type */, nullptr /* blob */,
-        blink::mojom::ServiceWorkerResponseError::kUnknown, response_time_,
-        std::string() /* cache_storage_cache_name */,
+        base::nullopt /* mime_type */, net::HttpRequestHeaders::kGetMethod,
+        nullptr /* blob */, blink::mojom::ServiceWorkerResponseError::kUnknown,
+        response_time_, std::string() /* cache_storage_cache_name */,
         std::vector<std::string>() /* cors_exposed_header_names */,
         nullptr /* side_data_blob */,
         nullptr /* side_data_blob_for_cache_put */,
diff --git a/content/browser/cache_storage/cache_storage_manager_unittest.cc b/content/browser/cache_storage/cache_storage_manager_unittest.cc
index 6bcf361..c25a0406 100644
--- a/content/browser/cache_storage/cache_storage_manager_unittest.cc
+++ b/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -662,9 +662,9 @@
     auto response = blink::mojom::FetchAPIResponse::New(
         std::vector<GURL>({request->url}), status_code, "OK", response_type,
         network::mojom::FetchResponseSource::kUnspecified, response_headers,
-        base::nullopt /* mime_type */, std::move(blob),
-        blink::mojom::ServiceWorkerResponseError::kUnknown, base::Time(),
-        std::string() /* cache_storage_cache_name */,
+        base::nullopt /* mime_type */, net::HttpRequestHeaders::kGetMethod,
+        std::move(blob), blink::mojom::ServiceWorkerResponseError::kUnknown,
+        base::Time(), std::string() /* cache_storage_cache_name */,
         std::vector<std::string>() /* cors_exposed_header_names */,
         nullptr /* side_data_blob */,
         nullptr /* side_data_blob_for_cache_put */,
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
index 61d2bc78..e356357 100644
--- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
+++ b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
@@ -48,6 +48,7 @@
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/disk_cache/disk_cache.h"
+#include "net/http/http_request_headers.h"
 #include "services/network/public/mojom/fetch_api.mojom.h"
 #include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/quota/padding_key.h"
@@ -420,12 +421,17 @@
   if (metadata.response().has_mime_type())
     mime_type = metadata.response().mime_type();
 
+  base::Optional<std::string> request_method;
+  if (metadata.response().has_request_method())
+    request_method = metadata.response().request_method();
+
   return blink::mojom::FetchAPIResponse::New(
       url_list, metadata.response().status_code(),
       metadata.response().status_text(),
       ProtoResponseTypeToFetchResponseType(metadata.response().response_type()),
       network::mojom::FetchResponseSource::kCacheStorage, headers, mime_type,
-      nullptr /* blob */, blink::mojom::ServiceWorkerResponseError::kUnknown,
+      request_method, nullptr /* blob */,
+      blink::mojom::ServiceWorkerResponseError::kUnknown,
       base::Time::FromInternalValue(metadata.response().response_time()),
       cache_name,
       std::vector<std::string>(
@@ -478,8 +484,12 @@
   const std::string& url = response->url_list(response->url_list_size() - 1);
   bool loaded_with_credentials = response->has_loaded_with_credentials() &&
                                  response->loaded_with_credentials();
+  const std::string& request_method = response->has_request_method()
+                                          ? response->request_method()
+                                          : net::HttpRequestHeaders::kGetMethod;
   return storage::ComputeResponsePadding(url, padding_key, side_data_size > 0,
-                                         loaded_with_credentials);
+                                         loaded_with_credentials,
+                                         request_method);
 }
 
 net::RequestPriority GetDiskCachePriority(
@@ -1065,7 +1075,8 @@
 
   if (owner_ != CacheStorageOwner::kBackgroundFetch &&
       (!options || !options->ignore_method) && request &&
-      !request->method.empty() && request->method != "GET") {
+      !request->method.empty() &&
+      request->method != net::HttpRequestHeaders::kGetMethod) {
     std::move(callback).Run(CacheStorageError::kSuccess,
                             std::make_unique<QueryCacheResults>());
     return;
@@ -1335,9 +1346,16 @@
   DCHECK_GE(side_data_size, 0);
   if (!ShouldPadResourceSize(response))
     return 0;
-  return storage::ComputeResponsePadding(response.url_list.back().spec(),
-                                         padding_key, side_data_size > 0,
-                                         response.loaded_with_credentials);
+  // Going forward we should always have a request method here since its
+  // impossible to create a no-cors Response via the constructor.  We must
+  // handle a missing method, however, since we may get a Response loaded
+  // from an old cache_storage instance without the data.
+  std::string request_method = response.request_method.has_value()
+                                   ? response.request_method.value()
+                                   : net::HttpRequestHeaders::kGetMethod;
+  return storage::ComputeResponsePadding(
+      response.url_list.back().spec(), padding_key, side_data_size > 0,
+      response.loaded_with_credentials, request_method);
 }
 
 // static
@@ -1794,6 +1812,10 @@
       put_context->response->was_fetched_via_spdy);
   if (put_context->response->mime_type.has_value())
     response_metadata->set_mime_type(put_context->response->mime_type.value());
+  if (put_context->response->request_method.has_value()) {
+    response_metadata->set_request_method(
+        put_context->response->request_method.value());
+  }
   response_metadata->set_response_time(
       put_context->response->response_time.ToInternalValue());
   for (ResponseHeaderMap::const_iterator it =
diff --git a/content/browser/form_controls_browsertest.cc b/content/browser/form_controls_browsertest.cc
index ac8107e..8f848be 100644
--- a/content/browser/form_controls_browsertest.cc
+++ b/content/browser/form_controls_browsertest.cc
@@ -134,14 +134,13 @@
   std::unique_ptr<base::test::ScopedFeatureList> feature_list_;
 };
 
+// Flaky: https://crbug.com/1091661.
 #if defined(OS_ANDROID)
-#define DISABLED_ON_ANDROID(name) DISABLED##name
+#define MAYBE_Checkbox DISABLED_CheckBox
 #else
-#define DISABLED_ON_ANDROID(name) name
+#define MAYBE_Checkbox CheckBox
 #endif
-
-// Flaky: https://crbug.com/1091661
-IN_PROC_BROWSER_TEST_F(FormControlsBrowserTest, DISABLED_ON_ANDROID(Checkbox)) {
+IN_PROC_BROWSER_TEST_F(FormControlsBrowserTest, MAYBE_Checkbox) {
   RunFormControlsTest(
       "form_controls_browsertest_checkbox",
       "<input type=checkbox>"
@@ -156,8 +155,13 @@
       /* screenshot_height */ 40);
 }
 
-// Flaky: https://crbug.com/1091661
-IN_PROC_BROWSER_TEST_F(FormControlsBrowserTest, DISABLED_ON_ANDROID(Radio)) {
+// Flaky: https://crbug.com/1091661.
+#if defined(OS_ANDROID)
+#define MAYBE_Radio DISABLED_Radio
+#else
+#define MAYBE_Radio Radio
+#endif
+IN_PROC_BROWSER_TEST_F(FormControlsBrowserTest, MAYBE_Radio) {
   RunFormControlsTest(
       "form_controls_browsertest_radio",
       "<input type=radio>"
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index 2df43b5f..1abf033 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -1092,7 +1092,7 @@
   // First make an existing committed entry.
   const GURL kExistingURL("http://foo/eh");
   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), kExistingURL);
-  main_test_rfh()->OnMessageReceived(FrameHostMsg_DidStopLoading(0));
+  main_test_rfh()->DidStopLoading();
   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   navigation_entry_committed_counter_ = 0;
 
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 2cf0ea5..11cd02d 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -1648,7 +1648,7 @@
 }
 
 void NavigationRequest::RegisterSubresourceOverride(
-    mojom::TransferrableURLLoaderPtr transferrable_loader) {
+    blink::mojom::TransferrableURLLoaderPtr transferrable_loader) {
   if (!transferrable_loader)
     return;
   if (!subresource_overrides_)
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index ccaa4324..3b72cc2 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -326,7 +326,7 @@
   bool IsSameProcess() override;
   int GetNavigationEntryOffset() override;
   void RegisterSubresourceOverride(
-      mojom::TransferrableURLLoaderPtr transferrable_loader) override;
+      blink::mojom::TransferrableURLLoaderPtr transferrable_loader) override;
   GlobalFrameRoutingId GetPreviousRenderFrameHostId() override;
   bool IsServedFromBackForwardCache() override;
   void SetIsOverridingUserAgent(bool override_ua) override;
@@ -1177,7 +1177,7 @@
   // See comment on accessor.
   const base::UnguessableToken devtools_navigation_token_;
 
-  base::Optional<std::vector<mojom::TransferrableURLLoaderPtr>>
+  base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
       subresource_overrides_;
 
   // The NavigationClient interface for that requested this navigation in the
diff --git a/content/browser/frame_host/navigator_unittest.cc b/content/browser/frame_host/navigator_unittest.cc
index 093a8b8..f21aa07 100644
--- a/content/browser/frame_host/navigator_unittest.cc
+++ b/content/browser/frame_host/navigator_unittest.cc
@@ -127,8 +127,7 @@
 
   contents()->NavigateAndCommit(kUrl1);
   EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive());
-  main_test_rfh()->OnMessageReceived(
-      FrameHostMsg_DidStopLoading(main_test_rfh()->GetRoutingID()));
+  main_test_rfh()->DidStopLoading();
 
   // Start a renderer-initiated non-user-initiated navigation.
   EXPECT_FALSE(main_test_rfh()->navigation_request());
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index f07d96e..f41263c2 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1617,7 +1617,6 @@
     IPC_MESSAGE_HANDLER(FrameHostMsg_Unload_ACK, OnUnloadACK)
     IPC_MESSAGE_HANDLER(FrameHostMsg_ContextMenu, OnContextMenu)
     IPC_MESSAGE_HANDLER(FrameHostMsg_VisualStateResponse, OnVisualStateResponse)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_DidStopLoading, OnDidStopLoading)
     IPC_MESSAGE_HANDLER(FrameHostMsg_SelectionChanged, OnSelectionChanged)
   IPC_END_MESSAGE_MAP()
 
@@ -2651,7 +2650,7 @@
 
   // The page is already loaded since it came from the cache, so fire the stop
   // loading event.
-  OnDidStopLoading();
+  DidStopLoading();
 }
 
 void RenderFrameHostImpl::DidCommitPerNavigationMojoInterfaceNavigation(
@@ -4264,33 +4263,6 @@
   delegate_->DOMContentLoaded(this);
 }
 
-void RenderFrameHostImpl::OnDidStopLoading() {
-  TRACE_EVENT1("navigation", "RenderFrameHostImpl::OnDidStopLoading",
-               "frame_tree_node", frame_tree_node_->frame_tree_node_id());
-
-  // This method should never be called when the frame is not loading.
-  // Unfortunately, it can happen if a history navigation happens during a
-  // BeforeUnload or Unload event.
-  // TODO(fdegans): Change this to a DCHECK after LoadEventProgress has been
-  // refactored in Blink. See crbug.com/466089
-  if (!is_loading_)
-    return;
-
-  was_discarded_ = false;
-  is_loading_ = false;
-
-  // If we have a PeakGpuMemoryTrack, close it as loading as stopped. It will
-  // asynchronously receive the statistics from the GPU process, and update
-  // UMA stats.
-  if (loading_mem_tracker_)
-    loading_mem_tracker_.reset();
-
-  // Only inform the FrameTreeNode of a change in load state if the load state
-  // of this RenderFrameHost is being tracked.
-  if (!IsPendingDeletion())
-    frame_tree_node_->DidStopLoading();
-}
-
 void RenderFrameHostImpl::OnSelectionChanged(const base::string16& text,
                                              uint32_t offset,
                                              const gfx::Range& range) {
@@ -4575,6 +4547,33 @@
       std::move(blob_url_loader_factory), params->impression);
 }
 
+void RenderFrameHostImpl::DidStopLoading() {
+  TRACE_EVENT1("navigation", "RenderFrameHostImpl::DidStopLoading",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id());
+
+  // This method should never be called when the frame is not loading.
+  // Unfortunately, it can happen if a history navigation happens during a
+  // BeforeUnload or Unload event.
+  // TODO(fdegans): Change this to a DCHECK after LoadEventProgress has been
+  // refactored in Blink. See crbug.com/466089
+  if (!is_loading_)
+    return;
+
+  was_discarded_ = false;
+  is_loading_ = false;
+
+  // If we have a PeakGpuMemoryTrack, close it as loading as stopped. It will
+  // asynchronously receive the statistics from the GPU process, and update
+  // UMA stats.
+  if (loading_mem_tracker_)
+    loading_mem_tracker_.reset();
+
+  // Only inform the FrameTreeNode of a change in load state if the load state
+  // of this RenderFrameHost is being tracked.
+  if (!IsPendingDeletion())
+    frame_tree_node_->DidStopLoading();
+}
+
 void RenderFrameHostImpl::GetSavableResourceLinksCallback(
     blink::mojom::GetSavableResourceLinksReplyPtr reply) {
   if (!reply) {
@@ -5640,7 +5639,7 @@
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     bool is_view_source,
     base::Optional<SubresourceLoaderParams> subresource_loader_params,
-    base::Optional<std::vector<mojom::TransferrableURLLoaderPtr>>
+    base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
         subresource_overrides,
     blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info,
     const base::UnguessableToken& devtools_navigation_token,
@@ -6474,12 +6473,12 @@
 void RenderFrameHostImpl::ResetLoadingState() {
   if (is_loading()) {
     // When pending deletion, just set the loading state to not loading.
-    // Otherwise, OnDidStopLoading will take care of that, as well as sending
+    // Otherwise, DidStopLoading will take care of that, as well as sending
     // notification to the FrameTreeNode about the change in loading state.
     if (IsPendingDeletion() || IsInBackForwardCache())
       is_loading_ = false;
     else
-      OnDidStopLoading();
+      DidStopLoading();
   }
 }
 
@@ -7045,7 +7044,8 @@
 }
 
 void RenderFrameHostImpl::CreateAudioInputStreamFactory(
-    mojo::PendingReceiver<mojom::RendererAudioInputStreamFactory> receiver) {
+    mojo::PendingReceiver<blink::mojom::RendererAudioInputStreamFactory>
+        receiver) {
   BrowserMainLoop* browser_main_loop = BrowserMainLoop::GetInstance();
   DCHECK(browser_main_loop);
   MediaStreamManager* msm = browser_main_loop->media_stream_manager();
@@ -7054,7 +7054,8 @@
 }
 
 void RenderFrameHostImpl::CreateAudioOutputStreamFactory(
-    mojo::PendingReceiver<mojom::RendererAudioOutputStreamFactory> receiver) {
+    mojo::PendingReceiver<blink::mojom::RendererAudioOutputStreamFactory>
+        receiver) {
   media::AudioSystem* audio_system =
       BrowserMainLoop::GetInstance()->audio_system();
   MediaStreamManager* media_stream_manager =
@@ -7923,8 +7924,8 @@
 
   // Set is loading to true now if it has not been set yet. This happens for
   // renderer-initiated same-document navigations. It can also happen when a
-  // racy DidStopLoading IPC resets the loading state that was set to true in
-  // CommitNavigation.
+  // racy DidStopLoading Mojo method resets the loading state that was set to
+  // true in CommitNavigation.
   if (!is_loading()) {
     bool was_loading = frame_tree()->IsLoading();
     is_loading_ = true;
@@ -8025,7 +8026,7 @@
   if (loading_mem_tracker_)
     loading_mem_tracker_->Cancel();
   // Main Frames will create the tracker, which will be triggered after we
-  // receive OnDidStopLoading.
+  // receive DidStopLoading.
   loading_mem_tracker_ = navigation_request->TakePeakGpuMemoryTracker();
 
   network::mojom::ClientSecurityStatePtr client_security_state =
@@ -8216,7 +8217,7 @@
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
         subresource_loader_factories,
-    base::Optional<std::vector<::content::mojom::TransferrableURLLoaderPtr>>
+    base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
         subresource_overrides,
     blink::mojom::ControllerServiceWorkerInfoPtr controller,
     blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info,
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index f339978..74f6470 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -62,7 +62,6 @@
 #include "content/public/browser/render_process_host_observer.h"
 #include "content/public/common/javascript_dialog_type.h"
 #include "content/public/common/previews_state.h"
-#include "content/public/common/transferrable_url_loader.mojom.h"
 #include "media/mojo/mojom/interface_factory.mojom-forward.h"
 #include "media/mojo/mojom/media_metrics_provider.mojom-forward.h"
 #include "media/mojo/services/media_metrics_provider.h"
@@ -114,6 +113,7 @@
 #include "third_party/blink/public/mojom/input/input_handler.mojom.h"
 #include "third_party/blink/public/mojom/installedapp/installed_app_provider.mojom.h"
 #include "third_party/blink/public/mojom/loader/resource_load_info.mojom-forward.h"
+#include "third_party/blink/public/mojom/loader/transferrable_url_loader.mojom.h"
 #include "third_party/blink/public/mojom/native_file_system/native_file_system_manager.mojom-forward.h"
 #include "third_party/blink/public/mojom/notifications/notification_service.mojom-forward.h"
 #include "third_party/blink/public/mojom/payments/payment_app.mojom.h"
@@ -892,7 +892,7 @@
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       bool is_view_source,
       base::Optional<SubresourceLoaderParams> subresource_loader_params,
-      base::Optional<std::vector<mojom::TransferrableURLLoaderPtr>>
+      base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
           subresource_overrides,
       blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info,
       const base::UnguessableToken& devtools_navigation_token,
@@ -1380,10 +1380,12 @@
 #endif
 
   void CreateAudioInputStreamFactory(
-      mojo::PendingReceiver<mojom::RendererAudioInputStreamFactory> receiver);
+      mojo::PendingReceiver<blink::mojom::RendererAudioInputStreamFactory>
+          receiver);
 
   void CreateAudioOutputStreamFactory(
-      mojo::PendingReceiver<mojom::RendererAudioOutputStreamFactory> receiver);
+      mojo::PendingReceiver<blink::mojom::RendererAudioOutputStreamFactory>
+          receiver);
 
   void GetFeatureObserver(
       mojo::PendingReceiver<blink::mojom::FeatureObserver> receiver);
@@ -1682,6 +1684,7 @@
 
   // mojom::FrameHost:
   void OpenURL(mojom::OpenURLParamsPtr params) override;
+  void DidStopLoading() override;
 
   void GetSavableResourceLinksFromRenderer();
 
@@ -1731,7 +1734,7 @@
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
           subresource_loader_factories,
-      base::Optional<std::vector<::content::mojom::TransferrableURLLoaderPtr>>
+      base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
           subresource_overrides,
       blink::mojom::ControllerServiceWorkerInfoPtr
           controller_service_worker_info,
@@ -1867,7 +1870,6 @@
 
   void OnForwardResourceTimingToParent(
       const ResourceTimingInfo& resource_timing);
-  void OnDidStopLoading();
   void OnSelectionChanged(const base::string16& text,
                           uint32_t offset,
                           const gfx::Range& range);
diff --git a/content/browser/hid/hid_service.cc b/content/browser/hid/hid_service.cc
index e182c460..efccfa37 100644
--- a/content/browser/hid/hid_service.cc
+++ b/content/browser/hid/hid_service.cc
@@ -66,7 +66,7 @@
 }
 
 void HidService::RegisterClient(
-    device::mojom::HidManagerClientAssociatedPtrInfo client) {
+    mojo::PendingAssociatedRemote<device::mojom::HidManagerClient> client) {
   clients_.Add(std::move(client));
 }
 
diff --git a/content/browser/hid/hid_service.h b/content/browser/hid/hid_service.h
index 07abd499..ead8fe0 100644
--- a/content/browser/hid/hid_service.h
+++ b/content/browser/hid/hid_service.h
@@ -39,7 +39,8 @@
 
   // blink::mojom::HidService:
   void RegisterClient(
-      device::mojom::HidManagerClientAssociatedPtrInfo client) override;
+      mojo::PendingAssociatedRemote<device::mojom::HidManagerClient> client)
+      override;
   void GetDevices(GetDevicesCallback callback) override;
   void RequestDevice(std::vector<blink::mojom::HidDeviceFilterPtr> filters,
                      RequestDeviceCallback callback) override;
diff --git a/content/browser/media/audio_input_stream_broker.cc b/content/browser/media/audio_input_stream_broker.cc
index 32bdf7e4..5e50a03 100644
--- a/content/browser/media/audio_input_stream_broker.cc
+++ b/content/browser/media/audio_input_stream_broker.cc
@@ -66,7 +66,7 @@
     media::UserInputMonitorBase* user_input_monitor,
     bool enable_agc,
     AudioStreamBroker::DeleterCallback deleter,
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
         renderer_factory_client)
     : AudioStreamBroker(render_process_id, render_frame_id),
       device_id_(device_id),
diff --git a/content/browser/media/audio_input_stream_broker.h b/content/browser/media/audio_input_stream_broker.h
index c77b7ed..51abc29 100644
--- a/content/browser/media/audio_input_stream_broker.h
+++ b/content/browser/media/audio_input_stream_broker.h
@@ -11,7 +11,6 @@
 #include "base/memory/weak_ptr.h"
 #include "content/browser/media/audio_stream_broker.h"
 #include "content/common/content_export.h"
-#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
 #include "media/base/audio_parameters.h"
 #include "media/mojo/mojom/audio_data_pipe.mojom.h"
 #include "media/mojo/mojom/audio_input_stream.mojom.h"
@@ -20,6 +19,7 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "services/audio/public/mojom/stream_factory.mojom.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
 
 namespace media {
 class UserInputMonitorBase;
@@ -42,7 +42,7 @@
       media::UserInputMonitorBase* user_input_monitor,
       bool enable_agc,
       AudioStreamBroker::DeleterCallback deleter,
-      mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+      mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
           renderer_factory_client);
 
   ~AudioInputStreamBroker() final;
@@ -74,7 +74,7 @@
 
   DeleterCallback deleter_;
 
-  mojo::Remote<mojom::RendererAudioInputStreamFactoryClient>
+  mojo::Remote<blink::mojom::RendererAudioInputStreamFactoryClient>
       renderer_factory_client_;
   mojo::Receiver<AudioInputStreamObserver> observer_receiver_{this};
   mojo::PendingReceiver<media::mojom::AudioInputStreamClient>
diff --git a/content/browser/media/audio_input_stream_broker_unittest.cc b/content/browser/media/audio_input_stream_broker_unittest.cc
index 6c028e0a..0f0c668 100644
--- a/content/browser/media/audio_input_stream_broker_unittest.cc
+++ b/content/browser/media/audio_input_stream_broker_unittest.cc
@@ -43,12 +43,12 @@
     base::MockCallback<base::OnceCallback<void(AudioStreamBroker*)>>>;
 
 class MockRendererAudioInputStreamFactoryClient
-    : public mojom::RendererAudioInputStreamFactoryClient {
+    : public blink::mojom::RendererAudioInputStreamFactoryClient {
  public:
   MockRendererAudioInputStreamFactoryClient() = default;
   ~MockRendererAudioInputStreamFactoryClient() override = default;
 
-  mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+  mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
   MakeRemote() {
     return receiver_.BindNewPipeAndPassRemote();
   }
@@ -71,7 +71,8 @@
   void CloseReceiver() { receiver_.reset(); }
 
  private:
-  mojo::Receiver<mojom::RendererAudioInputStreamFactoryClient> receiver_{this};
+  mojo::Receiver<blink::mojom::RendererAudioInputStreamFactoryClient> receiver_{
+      this};
   mojo::Remote<media::mojom::AudioInputStream> input_stream_;
   mojo::PendingReceiver<media::mojom::AudioInputStreamClient> client_receiver_;
   DISALLOW_COPY_AND_ASSIGN(MockRendererAudioInputStreamFactoryClient);
diff --git a/content/browser/media/audio_loopback_stream_broker.cc b/content/browser/media/audio_loopback_stream_broker.cc
index 034c0e5..d5826e4 100644
--- a/content/browser/media/audio_loopback_stream_broker.cc
+++ b/content/browser/media/audio_loopback_stream_broker.cc
@@ -25,7 +25,7 @@
     uint32_t shared_memory_count,
     bool mute_source,
     AudioStreamBroker::DeleterCallback deleter,
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
         renderer_factory_client)
     : AudioStreamBroker(render_process_id, render_frame_id),
       source_(source),
diff --git a/content/browser/media/audio_loopback_stream_broker.h b/content/browser/media/audio_loopback_stream_broker.h
index 36bbf04..6cdc94eb 100644
--- a/content/browser/media/audio_loopback_stream_broker.h
+++ b/content/browser/media/audio_loopback_stream_broker.h
@@ -45,7 +45,7 @@
       uint32_t shared_memory_count,
       bool mute_source,
       AudioStreamBroker::DeleterCallback deleter,
-      mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+      mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
           renderer_factory_client);
 
   ~AudioLoopbackStreamBroker() final;
@@ -76,7 +76,7 @@
   // loopback stream is running.
   base::Optional<AudioMutingSession> muter_;
 
-  mojo::Remote<mojom::RendererAudioInputStreamFactoryClient>
+  mojo::Remote<blink::mojom::RendererAudioInputStreamFactoryClient>
       renderer_factory_client_;
   mojo::Receiver<AudioInputStreamObserver> observer_receiver_{this};
   mojo::PendingReceiver<media::mojom::AudioInputStreamClient> client_receiver_;
diff --git a/content/browser/media/audio_loopback_stream_broker_unittest.cc b/content/browser/media/audio_loopback_stream_broker_unittest.cc
index 6e5edf9..8f558e7 100644
--- a/content/browser/media/audio_loopback_stream_broker_unittest.cc
+++ b/content/browser/media/audio_loopback_stream_broker_unittest.cc
@@ -59,12 +59,12 @@
     base::MockCallback<base::OnceCallback<void(AudioStreamBroker*)>>>;
 
 class MockRendererAudioInputStreamFactoryClient
-    : public mojom::RendererAudioInputStreamFactoryClient {
+    : public blink::mojom::RendererAudioInputStreamFactoryClient {
  public:
   MockRendererAudioInputStreamFactoryClient() = default;
   ~MockRendererAudioInputStreamFactoryClient() override {}
 
-  mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+  mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
   MakeRemote() {
     return receiver_.BindNewPipeAndPassRemote();
   }
@@ -88,7 +88,8 @@
   void CloseReceiver() { receiver_.reset(); }
 
  private:
-  mojo::Receiver<mojom::RendererAudioInputStreamFactoryClient> receiver_{this};
+  mojo::Receiver<blink::mojom::RendererAudioInputStreamFactoryClient> receiver_{
+      this};
   mojo::Remote<media::mojom::AudioInputStream> input_stream_;
   mojo::PendingReceiver<media::mojom::AudioInputStreamClient> client_receiver_;
 };
diff --git a/content/browser/media/audio_stream_broker.cc b/content/browser/media/audio_stream_broker.cc
index e4d9ad9..744855a7 100644
--- a/content/browser/media/audio_stream_broker.cc
+++ b/content/browser/media/audio_stream_broker.cc
@@ -33,7 +33,7 @@
       media::UserInputMonitorBase* user_input_monitor,
       bool enable_agc,
       AudioStreamBroker::DeleterCallback deleter,
-      mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+      mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
           renderer_factory_client) final {
     return std::make_unique<AudioInputStreamBroker>(
         render_process_id, render_frame_id, device_id, params,
@@ -49,7 +49,7 @@
       uint32_t shared_memory_count,
       bool mute_source,
       AudioStreamBroker::DeleterCallback deleter,
-      mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+      mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
           renderer_factory_client) final {
     return std::make_unique<AudioLoopbackStreamBroker>(
         render_process_id, render_frame_id, source, params, shared_memory_count,
diff --git a/content/browser/media/audio_stream_broker.h b/content/browser/media/audio_stream_broker.h
index fd80dd5..105dc77 100644
--- a/content/browser/media/audio_stream_broker.h
+++ b/content/browser/media/audio_stream_broker.h
@@ -13,10 +13,10 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "content/common/content_export.h"
-#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
 #include "media/mojo/mojom/audio_input_stream.mojom.h"
 #include "media/mojo/mojom/audio_output_stream.mojom.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
 
 namespace audio {
 namespace mojom {
@@ -106,7 +106,7 @@
       media::UserInputMonitorBase* user_input_monitor,
       bool enable_agc,
       AudioStreamBroker::DeleterCallback deleter,
-      mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+      mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
           renderer_factory_client) = 0;
 
   virtual std::unique_ptr<AudioStreamBroker> CreateAudioLoopbackStreamBroker(
@@ -117,7 +117,7 @@
       uint32_t shared_memory_count,
       bool mute_source,
       AudioStreamBroker::DeleterCallback deleter,
-      mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+      mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
           renderer_factory_client) = 0;
 
   virtual std::unique_ptr<AudioStreamBroker> CreateAudioOutputStreamBroker(
diff --git a/content/browser/media/forwarding_audio_stream_factory.cc b/content/browser/media/forwarding_audio_stream_factory.cc
index 2e33951..fba4ac53 100644
--- a/content/browser/media/forwarding_audio_stream_factory.cc
+++ b/content/browser/media/forwarding_audio_stream_factory.cc
@@ -79,7 +79,7 @@
     const media::AudioParameters& params,
     uint32_t shared_memory_count,
     bool enable_agc,
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
         renderer_factory_client) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
@@ -134,7 +134,7 @@
     const media::AudioParameters& params,
     uint32_t shared_memory_count,
     bool mute_source,
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
         renderer_factory_client) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(loopback_source);
diff --git a/content/browser/media/forwarding_audio_stream_factory.h b/content/browser/media/forwarding_audio_stream_factory.h
index 7ba03b9c..8fb6fd8 100644
--- a/content/browser/media/forwarding_audio_stream_factory.h
+++ b/content/browser/media/forwarding_audio_stream_factory.h
@@ -18,12 +18,12 @@
 #include "content/browser/media/audio_muting_session.h"
 #include "content/browser/media/audio_stream_broker.h"
 #include "content/common/content_export.h"
-#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "media/mojo/mojom/audio_output_stream.mojom.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "services/audio/public/mojom/stream_factory.mojom.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
 
 namespace media {
 class AudioParameters;
@@ -73,7 +73,7 @@
         const media::AudioParameters& params,
         uint32_t shared_memory_count,
         bool enable_agc,
-        mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+        mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
             renderer_factory_client);
 
     void AssociateInputAndOutputForAec(
@@ -95,7 +95,7 @@
         const media::AudioParameters& params,
         uint32_t shared_memory_count,
         bool mute_source,
-        mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+        mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
             renderer_factory_client);
 
     // Sets the muting state for all output streams created through this
diff --git a/content/browser/media/forwarding_audio_stream_factory_unittest.cc b/content/browser/media/forwarding_audio_stream_factory_unittest.cc
index fa9ae1c9..67081cc 100644
--- a/content/browser/media/forwarding_audio_stream_factory_unittest.cc
+++ b/content/browser/media/forwarding_audio_stream_factory_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/run_loop.h"
 #include "base/test/mock_callback.h"
 #include "base/unguessable_token.h"
-#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_renderer_host.h"
@@ -26,6 +25,7 @@
 #include "services/audio/public/mojom/stream_factory.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
 
 using ::testing::Test;
 using ::testing::Mock;
@@ -110,7 +110,7 @@
       media::UserInputMonitorBase* user_input_monitor,
       bool enable_agc,
       AudioStreamBroker::DeleterCallback deleter,
-      mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+      mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
           renderer_factory_client) final {
     std::unique_ptr<MockBroker> prepared_broker =
         std::move(prepared_input_stream_brokers_.front());
@@ -150,7 +150,7 @@
       uint32_t shared_memory_count,
       bool mute_source,
       AudioStreamBroker::DeleterCallback deleter,
-      mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+      mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
           renderer_factory_client) final {
     std::unique_ptr<MockBroker> prepared_broker =
         std::move(prepared_loopback_stream_brokers_.front());
@@ -258,7 +258,8 @@
 }  // namespace
 
 TEST_F(ForwardingAudioStreamFactoryTest, CreateInputStream_CreatesInputStream) {
-  mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client;
+  mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+      client;
   base::WeakPtr<MockBroker> broker = ExpectInputBrokerConstruction(main_rfh());
 
   ForwardingAudioStreamFactory factory(web_contents(),
@@ -276,7 +277,8 @@
 TEST_F(ForwardingAudioStreamFactoryTest,
        CreateLoopbackStream_CreatesLoopbackStream) {
   std::unique_ptr<WebContents> source_contents = CreateTestWebContents();
-  mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client;
+  mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+      client;
   base::WeakPtr<MockBroker> broker =
       ExpectLoopbackBrokerConstruction(main_rfh());
 
@@ -325,7 +327,8 @@
 
   {
     EXPECT_CALL(*main_rfh_broker, CreateStream(NotNull()));
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client;
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+        client;
     ignore_result(client.InitWithNewPipeAndPassReceiver());
     factory.core()->CreateInputStream(
         main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(),
@@ -335,7 +338,8 @@
   }
   {
     EXPECT_CALL(*other_rfh_broker, CreateStream(NotNull()));
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client;
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+        client;
     ignore_result(client.InitWithNewPipeAndPassReceiver());
     factory.core()->CreateInputStream(
         other_rfh()->GetProcess()->GetID(), other_rfh()->GetRoutingID(),
@@ -368,7 +372,8 @@
 
   {
     EXPECT_CALL(*main_rfh_broker, CreateStream(NotNull()));
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client;
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+        client;
     ignore_result(client.InitWithNewPipeAndPassReceiver());
     factory.core()->CreateLoopbackStream(
         main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(),
@@ -378,7 +383,8 @@
   }
   {
     EXPECT_CALL(*other_rfh_broker, CreateStream(NotNull()));
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client;
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+        client;
     ignore_result(client.InitWithNewPipeAndPassReceiver());
     factory.core()->CreateLoopbackStream(
         other_rfh()->GetProcess()->GetID(), other_rfh()->GetRoutingID(),
@@ -457,7 +463,7 @@
 
   {
     EXPECT_CALL(*main_rfh_input_broker, CreateStream(NotNull()));
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
         input_client;
     ignore_result(input_client.InitWithNewPipeAndPassReceiver());
     factory.core()->CreateInputStream(
@@ -468,7 +474,7 @@
   }
   {
     EXPECT_CALL(*other_rfh_input_broker, CreateStream(NotNull()));
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
         input_client;
     ignore_result(input_client.InitWithNewPipeAndPassReceiver());
     factory.core()->CreateInputStream(
@@ -480,7 +486,7 @@
 
   {
     EXPECT_CALL(*main_rfh_loopback_broker, CreateStream(NotNull()));
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
         input_client;
     ignore_result(input_client.InitWithNewPipeAndPassReceiver());
     factory.core()->CreateLoopbackStream(
@@ -491,7 +497,7 @@
   }
   {
     EXPECT_CALL(*other_rfh_loopback_broker, CreateStream(NotNull()));
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
         input_client;
     ignore_result(input_client.InitWithNewPipeAndPassReceiver());
     factory.core()->CreateLoopbackStream(
@@ -537,7 +543,7 @@
 }
 
 TEST_F(ForwardingAudioStreamFactoryTest, DestroyWebContents_DestroysStreams) {
-  mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+  mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
       input_client;
   base::WeakPtr<MockBroker> input_broker =
       ExpectInputBrokerConstruction(main_rfh());
@@ -590,7 +596,7 @@
 
   {
     EXPECT_CALL(*main_rfh_input_broker, CreateStream(NotNull()));
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
         input_client;
     ignore_result(input_client.InitWithNewPipeAndPassReceiver());
     factory.core()->CreateInputStream(
@@ -601,7 +607,7 @@
   }
   {
     EXPECT_CALL(*other_rfh_input_broker, CreateStream(NotNull()));
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
         input_client;
     ignore_result(input_client.InitWithNewPipeAndPassReceiver());
     factory.core()->CreateInputStream(
diff --git a/content/browser/media/in_process_audio_loopback_stream_creator.cc b/content/browser/media/in_process_audio_loopback_stream_creator.cc
index 2257a7c..9b99b38 100644
--- a/content/browser/media/in_process_audio_loopback_stream_creator.cc
+++ b/content/browser/media/in_process_audio_loopback_stream_creator.cc
@@ -12,7 +12,6 @@
 #include "base/location.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/web_contents/web_contents_impl.h"
-#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
@@ -20,16 +19,17 @@
 #include "media/base/user_input_monitor.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
 
 namespace content {
 
 namespace {
 
-// A mojom::RendererAudioInputStreamFactoryClient that holds a
+// A blink::mojom::RendererAudioInputStreamFactoryClient that holds a
 // AudioLoopbackStreamCreator::StreamCreatedCallback. The callback runs when the
 // requested audio stream is created.
 class StreamCreatedCallbackAdapter final
-    : public mojom::RendererAudioInputStreamFactoryClient {
+    : public blink::mojom::RendererAudioInputStreamFactoryClient {
  public:
   explicit StreamCreatedCallbackAdapter(
       const AudioLoopbackStreamCreator::StreamCreatedCallback& callback)
@@ -39,7 +39,7 @@
 
   ~StreamCreatedCallbackAdapter() override {}
 
-  // mojom::RendererAudioInputStreamFactoryClient implementation.
+  // blink::mojom::RendererAudioInputStreamFactoryClient implementation.
   void StreamCreated(
       mojo::PendingRemote<media::mojom::AudioInputStream> stream,
       mojo::PendingReceiver<media::mojom::AudioInputStreamClient>
@@ -63,7 +63,7 @@
     AudioStreamBroker::LoopbackSource* loopback_source,
     const media::AudioParameters& params,
     uint32_t total_segments,
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
         client_remote) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
@@ -76,7 +76,7 @@
     ForwardingAudioStreamFactory::Core* factory,
     const media::AudioParameters& params,
     uint32_t total_segments,
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
         client_remote) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
@@ -108,7 +108,8 @@
     uint32_t total_segments,
     const StreamCreatedCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client;
+  mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+      client;
   mojo::MakeSelfOwnedReceiver(
       std::make_unique<StreamCreatedCallbackAdapter>(callback),
       client.InitWithNewPipeAndPassReceiver());
diff --git a/content/browser/net/cross_origin_opener_policy_reporter.cc b/content/browser/net/cross_origin_opener_policy_reporter.cc
index 71e99b2..ff079b3 100644
--- a/content/browser/net/cross_origin_opener_policy_reporter.cc
+++ b/content/browser/net/cross_origin_opener_policy_reporter.cc
@@ -19,20 +19,20 @@
 
 namespace {
 
-constexpr char kUnsafeNone[] = "unsafe-none";
-constexpr char kSameOrigin[] = "same-origin";
-constexpr char kSameOriginPlusCoep[] = "same-origin-plus-coep";
-constexpr char kSameOriginAllowPopups[] = "same-origin-allow-popups";
-
-constexpr char kDisposition[] = "disposition";
 constexpr char kDispositionEnforce[] = "enforce";
 constexpr char kDispositionReporting[] = "reporting";
+constexpr char kDisposition[] = "disposition";
 constexpr char kDocumentURI[] = "document-uri";
+constexpr char kEffectivePolicy[] = "effective-policy";
 constexpr char kNavigationURI[] = "navigation-uri";
-constexpr char kViolationType[] = "violation-type";
+constexpr char kProperty[] = "property";
+constexpr char kSameOriginAllowPopups[] = "same-origin-allow-popups";
+constexpr char kSameOriginPlusCoep[] = "same-origin-plus-coep";
+constexpr char kSameOrigin[] = "same-origin";
+constexpr char kUnsafeNone[] = "unsafe-none";
 constexpr char kViolationTypeFromDocument[] = "navigation-from-document";
 constexpr char kViolationTypeToDocument[] = "navigation-to-document";
-constexpr char kEffectivePolicy[] = "effective-policy";
+constexpr char kViolationType[] = "violation-type";
 
 std::string CoopValueToString(
     network::mojom::CrossOriginOpenerPolicyValue coop_value) {
@@ -169,7 +169,28 @@
 
 void CrossOriginOpenerPolicyReporter::QueueAccessReport(
     const std::string& property) {
-  // TODO(arthursonzogni) Implement this.
+  // Cross-Origin-Opener-Policy-Report-Only is not required to provide
+  // endpoints.
+  if (!coop_.report_only_reporting_endpoint)
+    return;
+
+  const std::string& endpoint = coop_.report_only_reporting_endpoint.value();
+
+  DCHECK(base::FeatureList::IsEnabled(
+      network::features::kCrossOriginOpenerPolicyAccessReporting));
+
+  base::DictionaryValue body;
+  body.SetStringPath(kDisposition, kDispositionReporting);
+  body.SetStringPath(kEffectivePolicy,
+                     CoopValueToString(coop_.report_only_value));
+  body.SetStringPath(kProperty, property);
+  // TODO(arthursonzogni): Fill "blocked-window-url".
+  // TODO(arthursonzogni): Fill "source-file".
+  // TODO(arthursonzogni): Fill "line-no".
+  // TODO(arthursonzogni): Fill "col-no".
+  // TODO(arthursonzogni): Fill "violation-type".
+  storage_partition_->GetNetworkContext()->QueueReport(
+      "coop", endpoint, context_url_, base::nullopt, std::move(body));
 }
 
 void CrossOriginOpenerPolicyReporter::Clone(
diff --git a/content/browser/renderer_host/media/audio_input_stream_handle.cc b/content/browser/renderer_host/media/audio_input_stream_handle.cc
index 9401577..2010053 100644
--- a/content/browser/renderer_host/media/audio_input_stream_handle.cc
+++ b/content/browser/renderer_host/media/audio_input_stream_handle.cc
@@ -24,7 +24,7 @@
 }  // namespace
 
 AudioInputStreamHandle::AudioInputStreamHandle(
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
         client_pending_remote,
     media::MojoAudioInputStream::CreateDelegateCallback
         create_delegate_callback,
diff --git a/content/browser/renderer_host/media/audio_input_stream_handle.h b/content/browser/renderer_host/media/audio_input_stream_handle.h
index 799519a..b8dd45b2 100644
--- a/content/browser/renderer_host/media/audio_input_stream_handle.h
+++ b/content/browser/renderer_host/media/audio_input_stream_handle.h
@@ -9,7 +9,6 @@
 #include "base/macros.h"
 #include "base/sequence_checker.h"
 #include "content/common/content_export.h"
-#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
 #include "media/mojo/mojom/audio_data_pipe.mojom.h"
 #include "media/mojo/mojom/audio_input_stream.mojom.h"
 #include "media/mojo/services/mojo_audio_input_stream.h"
@@ -18,6 +17,7 @@
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/system/buffer.h"
 #include "mojo/public/cpp/system/handle.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
 
 namespace content {
 
@@ -30,7 +30,7 @@
   // |deleter_callback| will be called when encountering an error, in which
   // case |this| should be synchronously destructed by its owner.
   AudioInputStreamHandle(
-      mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+      mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
           client_pending_remote,
       media::MojoAudioInputStream::CreateDelegateCallback
           create_delegate_callback,
@@ -49,7 +49,8 @@
   SEQUENCE_CHECKER(sequence_checker_);
   const base::UnguessableToken stream_id_;
   DeleterCallback deleter_callback_;
-  mojo::Remote<mojom::RendererAudioInputStreamFactoryClient> client_remote_;
+  mojo::Remote<blink::mojom::RendererAudioInputStreamFactoryClient>
+      client_remote_;
   mojo::PendingRemote<media::mojom::AudioInputStream> pending_stream_;
   mojo::PendingReceiver<media::mojom::AudioInputStreamClient>
       pending_stream_client_;
diff --git a/content/browser/renderer_host/media/audio_input_stream_handle_unittest.cc b/content/browser/renderer_host/media/audio_input_stream_handle_unittest.cc
index f066c1d..278f7a8 100644
--- a/content/browser/renderer_host/media/audio_input_stream_handle_unittest.cc
+++ b/content/browser/renderer_host/media/audio_input_stream_handle_unittest.cc
@@ -44,7 +44,7 @@
 };
 
 class MockRendererAudioInputStreamFactoryClient
-    : public mojom::RendererAudioInputStreamFactoryClient {
+    : public blink::mojom::RendererAudioInputStreamFactoryClient {
  public:
   MOCK_METHOD0(Created, void());
 
@@ -129,9 +129,10 @@
  private:
   base::test::SingleThreadTaskEnvironment task_environment_;
   StrictMock<MockRendererAudioInputStreamFactoryClient> client_;
-  mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
+  mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
       client_pending_remote_;
-  mojo::Receiver<mojom::RendererAudioInputStreamFactoryClient> client_receiver_;
+  mojo::Receiver<blink::mojom::RendererAudioInputStreamFactoryClient>
+      client_receiver_;
   StrictMock<MockDeleter> deleter_;
   media::AudioInputDelegate::EventHandler* event_handler_ = nullptr;
   std::unique_ptr<AudioInputStreamHandle> handle_;
diff --git a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc
index acc14c6..27cdbf3 100644
--- a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc
+++ b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc
@@ -98,20 +98,22 @@
 }  // namespace
 
 class RenderFrameAudioInputStreamFactory::Core final
-    : public mojom::RendererAudioInputStreamFactory {
+    : public blink::mojom::RendererAudioInputStreamFactory {
  public:
-  Core(mojo::PendingReceiver<mojom::RendererAudioInputStreamFactory> receiver,
+  Core(mojo::PendingReceiver<blink::mojom::RendererAudioInputStreamFactory>
+           receiver,
        MediaStreamManager* media_stream_manager,
        RenderFrameHost* render_frame_host);
 
   ~Core() final;
 
-  void Init(
-      mojo::PendingReceiver<mojom::RendererAudioInputStreamFactory> receiver);
+  void Init(mojo::PendingReceiver<blink::mojom::RendererAudioInputStreamFactory>
+                receiver);
 
   // mojom::RendererAudioInputStreamFactory implementation.
   void CreateStream(
-      mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client,
+      mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+          client,
       const base::UnguessableToken& session_id,
       const media::AudioParameters& audio_params,
       bool automatic_gain_control,
@@ -122,7 +124,8 @@
       const std::string& output_device_id) final;
 
   void CreateLoopbackStream(
-      mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client,
+      mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+          client,
       const media::AudioParameters& audio_params,
       uint32_t shared_memory_count,
       bool disable_local_echo,
@@ -153,7 +156,8 @@
 };
 
 RenderFrameAudioInputStreamFactory::RenderFrameAudioInputStreamFactory(
-    mojo::PendingReceiver<mojom::RendererAudioInputStreamFactory> receiver,
+    mojo::PendingReceiver<blink::mojom::RendererAudioInputStreamFactory>
+        receiver,
     MediaStreamManager* media_stream_manager,
     RenderFrameHost* render_frame_host)
     : core_(new Core(std::move(receiver),
@@ -174,7 +178,8 @@
 }
 
 RenderFrameAudioInputStreamFactory::Core::Core(
-    mojo::PendingReceiver<mojom::RendererAudioInputStreamFactory> receiver,
+    mojo::PendingReceiver<blink::mojom::RendererAudioInputStreamFactory>
+        receiver,
     MediaStreamManager* media_stream_manager,
     RenderFrameHost* render_frame_host)
     : media_stream_manager_(media_stream_manager),
@@ -207,13 +212,15 @@
 }
 
 void RenderFrameAudioInputStreamFactory::Core::Init(
-    mojo::PendingReceiver<mojom::RendererAudioInputStreamFactory> receiver) {
+    mojo::PendingReceiver<blink::mojom::RendererAudioInputStreamFactory>
+        receiver) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   receiver_.Bind(std::move(receiver));
 }
 
 void RenderFrameAudioInputStreamFactory::Core::CreateStream(
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client,
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+        client,
     const base::UnguessableToken& session_id,
     const media::AudioParameters& audio_params,
     bool automatic_gain_control,
@@ -273,7 +280,8 @@
 }
 
 void RenderFrameAudioInputStreamFactory::Core::CreateLoopbackStream(
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client,
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+        client,
     const media::AudioParameters& audio_params,
     uint32_t shared_memory_count,
     bool disable_local_echo,
diff --git a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h
index 1fe77c4..3ae9d0db 100644
--- a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h
+++ b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h
@@ -9,8 +9,8 @@
 
 #include "base/macros.h"
 #include "content/common/content_export.h"
-#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
 
 namespace content {
 
@@ -26,7 +26,8 @@
 class CONTENT_EXPORT RenderFrameAudioInputStreamFactory final {
  public:
   RenderFrameAudioInputStreamFactory(
-      mojo::PendingReceiver<mojom::RendererAudioInputStreamFactory> receiver,
+      mojo::PendingReceiver<blink::mojom::RendererAudioInputStreamFactory>
+          receiver,
       MediaStreamManager* media_stream_manager,
       RenderFrameHost* render_frame_host);
 
diff --git a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
index d0837a3b..0ef2ddd 100644
--- a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
+++ b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
@@ -127,7 +127,7 @@
   };
 
   class FakeRendererAudioInputStreamFactoryClient
-      : public mojom::RendererAudioInputStreamFactoryClient {
+      : public blink::mojom::RendererAudioInputStreamFactoryClient {
    public:
     void StreamCreated(
         mojo::PendingRemote<media::mojom::AudioInputStream> stream,
@@ -187,7 +187,7 @@
 };
 
 TEST_F(MAYBE_RenderFrameAudioInputStreamFactoryTest, ConstructDestruct) {
-  mojo::Remote<mojom::RendererAudioInputStreamFactory> factory_remote;
+  mojo::Remote<blink::mojom::RendererAudioInputStreamFactory> factory_remote;
   RenderFrameAudioInputStreamFactory factory(
       factory_remote.BindNewPipeAndPassReceiver(), media_stream_manager_.get(),
       main_rfh());
@@ -195,7 +195,7 @@
 
 TEST_F(MAYBE_RenderFrameAudioInputStreamFactoryTest,
        CreateOpenedStream_ForwardsCall) {
-  mojo::Remote<mojom::RendererAudioInputStreamFactory> factory_remote;
+  mojo::Remote<blink::mojom::RendererAudioInputStreamFactory> factory_remote;
   RenderFrameAudioInputStreamFactory factory(
       factory_remote.BindNewPipeAndPassReceiver(), media_stream_manager_.get(),
       main_rfh());
@@ -206,7 +206,8 @@
           kDeviceName));
   base::RunLoop().RunUntilIdle();
 
-  mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client;
+  mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+      client;
   ignore_result(client.InitWithNewPipeAndPassReceiver());
   factory_remote->CreateStream(std::move(client), session_id, kParams, kAGC,
                                kSharedMemoryCount);
@@ -219,7 +220,7 @@
 TEST_F(MAYBE_RenderFrameAudioInputStreamFactoryTest,
        CreateWebContentsCapture_ForwardsCall) {
   std::unique_ptr<WebContents> source_contents = CreateTestWebContents();
-  mojo::Remote<mojom::RendererAudioInputStreamFactory> factory_remote;
+  mojo::Remote<blink::mojom::RendererAudioInputStreamFactory> factory_remote;
   RenderFrameAudioInputStreamFactory factory(
       factory_remote.BindNewPipeAndPassReceiver(), media_stream_manager_.get(),
       main_rfh());
@@ -233,7 +234,8 @@
           capture_id.ToString(), kDeviceName));
   base::RunLoop().RunUntilIdle();
 
-  mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client;
+  mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+      client;
   ignore_result(client.InitWithNewPipeAndPassReceiver());
   factory_remote->CreateStream(std::move(client), session_id, kParams, kAGC,
                                kSharedMemoryCount);
@@ -246,7 +248,7 @@
 TEST_F(MAYBE_RenderFrameAudioInputStreamFactoryTest,
        CreateWebContentsCaptureAfterCaptureSourceDestructed_Fails) {
   std::unique_ptr<WebContents> source_contents = CreateTestWebContents();
-  mojo::Remote<mojom::RendererAudioInputStreamFactory> factory_remote;
+  mojo::Remote<blink::mojom::RendererAudioInputStreamFactory> factory_remote;
   RenderFrameAudioInputStreamFactory factory(
       factory_remote.BindNewPipeAndPassReceiver(), media_stream_manager_.get(),
       main_rfh());
@@ -261,7 +263,8 @@
   base::RunLoop().RunUntilIdle();
 
   source_contents.reset();
-  mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client;
+  mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+      client;
   ignore_result(client.InitWithNewPipeAndPassReceiver());
   factory_remote->CreateStream(std::move(client), session_id, kParams, kAGC,
                                kSharedMemoryCount);
@@ -273,13 +276,14 @@
 
 TEST_F(MAYBE_RenderFrameAudioInputStreamFactoryTest,
        CreateStreamWithoutValidSessionId_Fails) {
-  mojo::Remote<mojom::RendererAudioInputStreamFactory> factory_remote;
+  mojo::Remote<blink::mojom::RendererAudioInputStreamFactory> factory_remote;
   RenderFrameAudioInputStreamFactory factory(
       factory_remote.BindNewPipeAndPassReceiver(), media_stream_manager_.get(),
       main_rfh());
 
   base::UnguessableToken session_id = base::UnguessableToken::Create();
-  mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client;
+  mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+      client;
   ignore_result(client.InitWithNewPipeAndPassReceiver());
   factory_remote->CreateStream(std::move(client), session_id, kParams, kAGC,
                                kSharedMemoryCount);
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
index 5f2a7fc6..4099192 100644
--- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
+++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
@@ -34,17 +34,19 @@
 namespace content {
 
 class RenderFrameAudioOutputStreamFactory::Core final
-    : public mojom::RendererAudioOutputStreamFactory {
+    : public blink::mojom::RendererAudioOutputStreamFactory {
  public:
   Core(RenderFrameHost* frame,
        media::AudioSystem* audio_system,
        MediaStreamManager* media_stream_manager,
-       mojo::PendingReceiver<mojom::RendererAudioOutputStreamFactory> receiver);
+       mojo::PendingReceiver<blink::mojom::RendererAudioOutputStreamFactory>
+           receiver);
 
   ~Core() final = default;
 
   void Init(
-      mojo::PendingReceiver<mojom::RendererAudioOutputStreamFactory> receiver);
+      mojo::PendingReceiver<blink::mojom::RendererAudioOutputStreamFactory>
+          receiver);
 
   size_t current_number_of_providers_for_testing() {
     return stream_providers_.size();
@@ -107,7 +109,7 @@
       base::flat_set<std::unique_ptr<media::mojom::AudioOutputStreamProvider>,
                      base::UniquePtrComparator>;
 
-  // mojom::RendererAudioOutputStreamFactory implementation.
+  // blink::mojom::RendererAudioOutputStreamFactory implementation.
   void RequestDeviceAuthorization(
       mojo::PendingReceiver<media::mojom::AudioOutputStreamProvider>
           provider_receiver,
@@ -134,7 +136,8 @@
   const int frame_id_;
   AudioOutputAuthorizationHandler authorization_handler_;
 
-  mojo::Receiver<mojom::RendererAudioOutputStreamFactory> receiver_{this};
+  mojo::Receiver<blink::mojom::RendererAudioOutputStreamFactory> receiver_{
+      this};
   // Always null-check this weak pointer before dereferencing it.
   base::WeakPtr<ForwardingAudioStreamFactory::Core> forwarding_factory_;
 
@@ -154,7 +157,8 @@
     RenderFrameHost* frame,
     media::AudioSystem* audio_system,
     MediaStreamManager* media_stream_manager,
-    mojo::PendingReceiver<mojom::RendererAudioOutputStreamFactory> receiver)
+    mojo::PendingReceiver<blink::mojom::RendererAudioOutputStreamFactory>
+        receiver)
     : core_(new Core(frame,
                      audio_system,
                      media_stream_manager,
@@ -183,7 +187,8 @@
     RenderFrameHost* frame,
     media::AudioSystem* audio_system,
     MediaStreamManager* media_stream_manager,
-    mojo::PendingReceiver<mojom::RendererAudioOutputStreamFactory> receiver)
+    mojo::PendingReceiver<blink::mojom::RendererAudioOutputStreamFactory>
+        receiver)
     : process_id_(frame->GetProcess()->GetID()),
       frame_id_(frame->GetRoutingID()),
       authorization_handler_(audio_system, media_stream_manager, process_id_) {
@@ -209,7 +214,8 @@
 }
 
 void RenderFrameAudioOutputStreamFactory::Core::Init(
-    mojo::PendingReceiver<mojom::RendererAudioOutputStreamFactory> receiver) {
+    mojo::PendingReceiver<blink::mojom::RendererAudioOutputStreamFactory>
+        receiver) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   receiver_.Bind(std::move(receiver));
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h
index 34bd3afa..bc30cad 100644
--- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h
+++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h
@@ -10,8 +10,8 @@
 
 #include "base/macros.h"
 #include "content/common/content_export.h"
-#include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_output_stream_factory.mojom.h"
 
 namespace media {
 class AudioSystem;
@@ -46,7 +46,8 @@
       RenderFrameHost* frame,
       media::AudioSystem* audio_system,
       MediaStreamManager* media_stream_manager,
-      mojo::PendingReceiver<mojom::RendererAudioOutputStreamFactory> receiver);
+      mojo::PendingReceiver<blink::mojom::RendererAudioOutputStreamFactory>
+          receiver);
 
   ~RenderFrameAudioOutputStreamFactory();
 
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
index dbe40d2..1533544e 100644
--- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
+++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
@@ -121,7 +121,7 @@
 };
 
 TEST_F(RenderFrameAudioOutputStreamFactoryTest, ConstructDestruct) {
-  mojo::Remote<mojom::RendererAudioOutputStreamFactory> factory_remote;
+  mojo::Remote<blink::mojom::RendererAudioOutputStreamFactory> factory_remote;
   RenderFrameAudioOutputStreamFactory factory(
       main_rfh(), audio_system_.get(), media_stream_manager_.get(),
       factory_remote.BindNewPipeAndPassReceiver());
@@ -129,7 +129,7 @@
 
 TEST_F(RenderFrameAudioOutputStreamFactoryTest,
        RequestDeviceAuthorizationForDefaultDevice_StatusOk) {
-  mojo::Remote<mojom::RendererAudioOutputStreamFactory> factory_remote;
+  mojo::Remote<blink::mojom::RendererAudioOutputStreamFactory> factory_remote;
   RenderFrameAudioOutputStreamFactory factory(
       main_rfh(), audio_system_.get(), media_stream_manager_.get(),
       factory_remote.BindNewPipeAndPassReceiver());
@@ -151,7 +151,7 @@
 TEST_F(
     RenderFrameAudioOutputStreamFactoryTest,
     RequestDeviceAuthorizationForDefaultDeviceAndDestroyProviderPtr_CleansUp) {
-  mojo::Remote<mojom::RendererAudioOutputStreamFactory> factory_remote;
+  mojo::Remote<blink::mojom::RendererAudioOutputStreamFactory> factory_remote;
   RenderFrameAudioOutputStreamFactory factory(
       main_rfh(), audio_system_.get(), media_stream_manager_.get(),
       factory_remote.BindNewPipeAndPassReceiver());
@@ -174,7 +174,7 @@
 TEST_F(
     RenderFrameAudioOutputStreamFactoryTest,
     RequestDeviceAuthorizationForNondefaultDeviceWithoutAuthorization_Fails) {
-  mojo::Remote<mojom::RendererAudioOutputStreamFactory> factory_remote;
+  mojo::Remote<blink::mojom::RendererAudioOutputStreamFactory> factory_remote;
   RenderFrameAudioOutputStreamFactory factory(
       main_rfh(), audio_system_.get(), media_stream_manager_.get(),
       factory_remote.BindNewPipeAndPassReceiver());
@@ -195,7 +195,7 @@
 
 TEST_F(RenderFrameAudioOutputStreamFactoryTest,
        CreateStream_CreatesStreamAndFreesProvider) {
-  mojo::Remote<mojom::RendererAudioOutputStreamFactory> factory_remote;
+  mojo::Remote<blink::mojom::RendererAudioOutputStreamFactory> factory_remote;
   RenderFrameAudioOutputStreamFactory factory(
       main_rfh(), audio_system_.get(), media_stream_manager_.get(),
       factory_remote.BindNewPipeAndPassReceiver());
@@ -227,7 +227,7 @@
   MockAuthorizationCallback mock_callback;
 
   {
-    mojo::Remote<mojom::RendererAudioOutputStreamFactory> factory_remote;
+    mojo::Remote<blink::mojom::RendererAudioOutputStreamFactory> factory_remote;
     RenderFrameAudioOutputStreamFactory factory(
         main_rfh(), audio_system_.get(), media_stream_manager_.get(),
         factory_remote.BindNewPipeAndPassReceiver());
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 5f792f5..2f74aa8 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -41,7 +41,6 @@
 #include "content/common/associated_interfaces.mojom.h"
 #include "content/common/child_process.mojom.h"
 #include "content/common/content_export.h"
-#include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
 #include "content/common/renderer.mojom.h"
 #include "content/common/renderer_host.mojom.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -82,6 +81,7 @@
 #include "third_party/blink/public/mojom/filesystem/file_system.mojom.h"
 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-shared.h"
 #include "third_party/blink/public/mojom/loader/code_cache.mojom.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_output_stream_factory.mojom.h"
 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 #include "third_party/blink/public/mojom/native_io/native_io.mojom-forward.h"
 #include "third_party/blink/public/mojom/peerconnection/peer_connection_tracker.mojom.h"
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index c88e3eb3..2daf04a1e 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -1037,6 +1037,84 @@
   EXPECT_EQ(301, fetch_response->status_code);
 }
 
+// Check if a fetch event can be failed without crashing if starting a service
+// worker fails. This is a regression test for https://crbug.com/1106977.
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest,
+                       DispatchFetchEventToBrokenWorker) {
+  // Setup the server so that the test doesn't crash when tearing down.
+  StartServerAndNavigateToSetup();
+  // This test is meaningful only when ServiceWorkerOnUI is enabled.
+  if (!ServiceWorkerContext::IsServiceWorkerOnUIEnabled())
+    return;
+
+  WorkerRunningStatusObserver observer(public_context());
+  EXPECT_TRUE(NavigateToURL(shell(),
+                            embedded_test_server()->GetURL(
+                                "/service_worker/create_service_worker.html")));
+  EXPECT_EQ("DONE", EvalJs(shell(), "register('fetch_event.js');"));
+  observer.WaitUntilRunning();
+
+  ASSERT_TRUE(
+      BrowserThread::CurrentlyOn(ServiceWorkerContext::GetCoreThreadId()));
+  scoped_refptr<ServiceWorkerVersion> version =
+      wrapper()->GetLiveVersion(observer.version_id());
+  EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version->running_status());
+
+  {
+    base::RunLoop loop;
+    version->StopWorker(loop.QuitClosure());
+    loop.Run();
+    EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version->running_status());
+  }
+
+  // Set a non-existent resource to the version.
+  std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> resources;
+  resources.push_back(storage::mojom::ServiceWorkerResourceRecord::New(
+      123456789, version->script_url(), 100));
+  version->script_cache_map()->resource_map_.clear();
+  version->script_cache_map()->SetResources(resources);
+
+  bool is_prepare_callback_called = false;
+  base::RunLoop fetch_loop;
+  blink::ServiceWorkerStatusCode fetch_status;
+  ServiceWorkerFetchDispatcher::FetchEventResult fetch_result;
+
+  auto request = blink::mojom::FetchAPIRequest::New();
+  request->url = embedded_test_server()->GetURL("/service_worker/in-scope");
+  request->method = "GET";
+  request->is_main_resource_load = true;
+  auto dispatcher = std::make_unique<ServiceWorkerFetchDispatcher>(
+      std::move(request), blink::mojom::ResourceType::kMainFrame,
+      /*client_id=*/base::GenerateGUID(), version,
+      base::BindLambdaForTesting([&]() { is_prepare_callback_called = true; }),
+      base::BindLambdaForTesting(
+          [&](blink::ServiceWorkerStatusCode status,
+              ServiceWorkerFetchDispatcher::FetchEventResult result,
+              blink::mojom::FetchAPIResponsePtr response,
+              blink::mojom::ServiceWorkerStreamHandlePtr,
+              blink::mojom::ServiceWorkerFetchEventTimingPtr,
+              scoped_refptr<ServiceWorkerVersion>) {
+            fetch_status = status;
+            fetch_result = result;
+            fetch_loop.Quit();
+          }),
+      /*is_offline_capability_check=*/false);
+
+  // DispatchFetchEvent is called synchronously with dispatcher->Run() even if
+  // the worker is stopped.
+  dispatcher->Run();
+  EXPECT_TRUE(is_prepare_callback_called);
+
+  // Check if the fetch event fails due to error of reading the resource.
+  fetch_loop.Run();
+  EXPECT_EQ(blink::ServiceWorkerStatusCode::kErrorDiskCache, fetch_status);
+  EXPECT_EQ(ServiceWorkerFetchDispatcher::FetchEventResult::kShouldFallback,
+            fetch_result);
+
+  // Make sure that no crash happens in the remaining tasks.
+  base::RunLoop().RunUntilIdle();
+}
+
 class ServiceWorkerEagerCacheStorageSetupTest
     : public ServiceWorkerBrowserTest {
  public:
diff --git a/content/browser/service_worker/service_worker_disk_cache.cc b/content/browser/service_worker/service_worker_disk_cache.cc
index 7507333..723b197 100644
--- a/content/browser/service_worker/service_worker_disk_cache.cc
+++ b/content/browser/service_worker/service_worker_disk_cache.cc
@@ -6,7 +6,6 @@
 
 #include <utility>
 
-#include "content/common/service_worker/service_worker_utils.h"
 #include "net/base/io_buffer.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 
@@ -25,16 +24,29 @@
     return;
   }
 
-  DCHECK(io_buffer->http_info);
-  auto response_and_metadata =
-      ServiceWorkerUtils::CreateResourceResponseHeadAndMetadata(
-          io_buffer->http_info.get(),
-          /*options=*/network::mojom::kURLLoadOptionSendSSLInfoWithResponse,
-          /*request_start_time=*/base::TimeTicks(),
-          /*response_start_time=*/base::TimeTicks::Now(),
-          io_buffer->response_data_size);
-  std::move(callback).Run(result, std::move(response_and_metadata.head),
-                          std::move(response_and_metadata.metadata));
+  const net::HttpResponseInfo* http_info = io_buffer->http_info.get();
+  DCHECK(http_info);
+  DCHECK(http_info->headers);
+
+  auto head = network::mojom::URLResponseHead::New();
+  head->request_start = base::TimeTicks();
+  head->response_start = base::TimeTicks::Now();
+  head->request_time = http_info->request_time;
+  head->response_time = http_info->response_time;
+  head->headers = http_info->headers;
+  head->headers->GetMimeType(&head->mime_type);
+  head->headers->GetCharset(&head->charset);
+  head->content_length = io_buffer->response_data_size;
+  head->was_fetched_via_spdy = http_info->was_fetched_via_spdy;
+  head->was_alpn_negotiated = http_info->was_alpn_negotiated;
+  head->connection_info = http_info->connection_info;
+  head->alpn_negotiated_protocol = http_info->alpn_negotiated_protocol;
+  head->remote_endpoint = http_info->remote_endpoint;
+  head->cert_status = http_info->ssl_info.cert_status;
+  head->ssl_info = http_info->ssl_info;
+
+  std::move(callback).Run(result, std::move(head),
+                          std::move(http_info->metadata));
 }
 
 }  // namespace
@@ -63,11 +75,6 @@
     const network::mojom::URLResponseHead& response_head,
     int response_data_size,
     net::CompletionOnceCallback callback) {
-  // This is copied from CreateHttpResponseInfoAndCheckHeaders().
-  // TODO(bashi): Use CreateHttpResponseInfoAndCheckHeaders()
-  // once we remove URLResponseHead -> HttpResponseInfo -> URLResponseHead
-  // conversion, which drops some information needed for validation
-  // (e.g. mime type).
   auto response_info = std::make_unique<net::HttpResponseInfo>();
   response_info->headers = response_head.headers;
   if (response_head.ssl_info.has_value())
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index c797a8e5..3b29f0d 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -625,6 +625,10 @@
 void ServiceWorkerFetchDispatcher::DidFailToDispatch(
     std::unique_ptr<ResponseCallback> response_callback,
     blink::ServiceWorkerStatusCode status) {
+  // Fetch dispatcher can be completed at this point due to a failure of
+  // starting up a worker. In that case, let's simply ignore it.
+  if (IsCompleted())
+    return;
   DidFail(status);
 }
 
@@ -772,6 +776,10 @@
   return request_.is_null();
 }
 
+bool ServiceWorkerFetchDispatcher::IsCompleted() const {
+  return fetch_callback_.is_null();
+}
+
 // static
 void ServiceWorkerFetchDispatcher::OnFetchEventFinished(
     ServiceWorkerVersion* version,
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.h b/content/browser/service_worker/service_worker_fetch_dispatcher.h
index 87ffce31..dfc319b 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.h
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.h
@@ -110,6 +110,7 @@
   ServiceWorkerMetrics::EventType GetEventType() const;
 
   bool IsEventDispatched() const;
+  bool IsCompleted() const;
 
   blink::mojom::FetchAPIRequestPtr request_;
   std::string client_id_;
diff --git a/content/browser/service_worker/service_worker_script_cache_map.h b/content/browser/service_worker/service_worker_script_cache_map.h
index 18a44c4..ad0d143f 100644
--- a/content/browser/service_worker/service_worker_script_cache_map.h
+++ b/content/browser/service_worker/service_worker_script_cache_map.h
@@ -74,6 +74,8 @@
   friend class ServiceWorkerVersion;
   friend class ServiceWorkerVersionBrowserTest;
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerReadFromCacheJobTest, ResourceNotFound);
+  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerBrowserTest,
+                           DispatchFetchEventToBrokenWorker);
 
   ServiceWorkerScriptCacheMap(
       ServiceWorkerVersion* owner,
diff --git a/content/browser/service_worker/service_worker_test_utils.cc b/content/browser/service_worker/service_worker_test_utils.cc
index d1e05bd..b5b5ea2 100644
--- a/content/browser/service_worker/service_worker_test_utils.cc
+++ b/content/browser/service_worker/service_worker_test_utils.cc
@@ -27,7 +27,6 @@
 #include "content/common/frame_messages.h"
 #include "content/common/frame_messages.mojom.h"
 #include "content/public/common/child_process_host.h"
-#include "content/public/common/transferrable_url_loader.mojom.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -39,6 +38,7 @@
 #include "net/base/test_completion_callback.h"
 #include "net/http/http_response_info.h"
 #include "third_party/blink/public/common/loader/throttling_url_loader.h"
+#include "third_party/blink/public/mojom/loader/transferrable_url_loader.mojom.h"
 
 namespace content {
 
@@ -121,7 +121,7 @@
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
           subresource_loader_factories,
-      base::Optional<std::vector<::content::mojom::TransferrableURLLoaderPtr>>
+      base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
           subresource_overrides,
       blink::mojom::ControllerServiceWorkerInfoPtr
           controller_service_worker_info,
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index f8940750..a13ebeb 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -29,10 +29,12 @@
 #include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/frame_host/navigation_request.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/web_contents/web_contents_view.h"
+#include "content/common/frame.mojom-test-utils.h"
 #include "content/common/frame_messages.h"
 #include "content/common/page_messages.h"
 #include "content/common/unfreezable_frame_messages.h"
@@ -4247,4 +4249,53 @@
   EXPECT_FALSE(web_contents->ShouldIgnoreUnresponsiveRenderer());
 }
 
+// Intercept calls to RenderFramHostImpl's DidStopLoading mojo method.
+class DidStopLoadingInterceptor : public mojom::FrameHostInterceptorForTesting {
+ public:
+  explicit DidStopLoadingInterceptor(RenderFrameHostImpl* render_frame_host)
+      : render_frame_host_(render_frame_host) {
+    render_frame_host_->frame_host_receiver_for_testing().SwapImplForTesting(
+        this);
+  }
+
+  ~DidStopLoadingInterceptor() override = default;
+
+  mojom::FrameHost* GetForwardingInterface() override {
+    return render_frame_host_;
+  }
+
+  void DidStopLoading() override {
+    static_cast<RenderProcessHostImpl*>(render_frame_host_->GetProcess())
+        ->mark_child_process_activity_time();
+    render_frame_host_->DidStopLoading();
+  }
+
+ private:
+  RenderFrameHostImpl* render_frame_host_;
+
+  DISALLOW_COPY_AND_ASSIGN(DidStopLoadingInterceptor);
+};
+
+// Test that get_process_idle_time() returns reasonable values when compared
+// with time deltas measured locally.
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, RenderIdleTime) {
+  EXPECT_TRUE(embedded_test_server()->Start());
+
+  base::TimeTicks start = base::TimeTicks::Now();
+  DidStopLoadingInterceptor interceptor(
+      static_cast<content::RenderFrameHostImpl*>(
+          shell()->web_contents()->GetMainFrame()));
+
+  GURL test_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), test_url));
+
+  base::TimeDelta renderer_td = shell()
+                                    ->web_contents()
+                                    ->GetMainFrame()
+                                    ->GetProcess()
+                                    ->GetChildProcessIdleTime();
+  base::TimeDelta browser_td = base::TimeTicks::Now() - start;
+  EXPECT_TRUE(browser_td >= renderer_td);
+}
+
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index 05dd899..23f89d20 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -2122,8 +2122,7 @@
                                        ui::PAGE_TRANSITION_AUTO_SUBFRAME);
   EXPECT_TRUE(contents()->IsLoading());
   EXPECT_FALSE(contents()->IsLoadingToDifferentDocument());
-  subframe->OnMessageReceived(
-      FrameHostMsg_DidStopLoading(subframe->GetRoutingID()));
+  subframe->DidStopLoading();
   EXPECT_FALSE(contents()->IsLoading());
 }
 
@@ -2162,8 +2161,7 @@
   // navigation in the current RenderFrameHost. There should still be a pending
   // RenderFrameHost and the WebContents should still be loading.
   same_process_navigation->Commit();
-  current_rfh->OnMessageReceived(
-      FrameHostMsg_DidStopLoading(current_rfh->GetRoutingID()));
+  current_rfh->DidStopLoading();
   EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh);
   EXPECT_TRUE(contents()->IsLoading());
 
@@ -2183,8 +2181,7 @@
 
   // Simulate the new current RenderFrameHost DidStopLoading. The WebContents
   // should now have stopped loading.
-  new_current_rfh->OnMessageReceived(
-      FrameHostMsg_DidStopLoading(new_current_rfh->GetRoutingID()));
+  new_current_rfh->DidStopLoading();
   EXPECT_EQ(main_test_rfh(), new_current_rfh);
   EXPECT_FALSE(contents()->IsLoading());
 }
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 54959ca..69b886d 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -440,8 +440,6 @@
     "histogram_fetcher.mojom",
     "input/input_injector.mojom",
     "media/media_log_records.mojom",
-    "media/renderer_audio_input_stream_factory.mojom",
-    "media/renderer_audio_output_stream_factory.mojom",
     "native_types.mojom",
     "navigation_client.mojom",
     "navigation_params.mojom",
diff --git a/content/common/background_fetch/background_fetch_types.cc b/content/common/background_fetch/background_fetch_types.cc
index b692336..eb94075 100644
--- a/content/common/background_fetch/background_fetch_types.cc
+++ b/content/common/background_fetch/background_fetch_types.cc
@@ -32,7 +32,8 @@
   return blink::mojom::FetchAPIResponse::New(
       response->url_list, response->status_code, response->status_text,
       response->response_type, response->response_source, response->headers,
-      response->mime_type, CloneSerializedBlob(response->blob), response->error,
+      response->mime_type, response->request_method,
+      CloneSerializedBlob(response->blob), response->error,
       response->response_time, response->cache_storage_cache_name,
       response->cors_exposed_header_names,
       CloneSerializedBlob(response->side_data_blob),
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index eff5643a..bba4089 100644
--- a/content/common/frame.mojom
+++ b/content/common/frame.mojom
@@ -11,7 +11,6 @@
 import "content/common/navigation_params.mojom";
 import "content/common/web_ui.mojom";
 import "content/public/common/browser_controls_state.mojom";
-import "content/public/common/transferrable_url_loader.mojom";
 import "content/public/common/window_container_type.mojom";
 import "mojo/public/mojom/base/file_path.mojom";
 import "mojo/public/mojom/base/string16.mojom";
@@ -546,4 +545,7 @@
 
   // Requests that the given URL be opened in the specified manner.
   OpenURL(OpenURLParams params);
+
+  // Called when the renderer is done loading a frame.
+  DidStopLoading();
 };
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index e5632a9..baec093 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -466,9 +466,6 @@
 // detached from the DOM.
 IPC_MESSAGE_ROUTED0(FrameHostMsg_Detach)
 
-// Sent when the renderer is done loading a page.
-IPC_MESSAGE_ROUTED0(FrameHostMsg_DidStopLoading)
-
 #if BUILDFLAG(ENABLE_PLUGINS)
 // Notification sent from a renderer to the browser that a Pepper plugin
 // instance is created in the DOM.
diff --git a/content/common/navigation_client.mojom b/content/common/navigation_client.mojom
index fe78527..596de59 100644
--- a/content/common/navigation_client.mojom
+++ b/content/common/navigation_client.mojom
@@ -10,9 +10,9 @@
 import "services/network/public/mojom/url_loader_factory.mojom";
 import "content/common/frame_messages.mojom";
 import "content/common/navigation_params.mojom";
-import "content/public/common/transferrable_url_loader.mojom";
 import "mojo/public/mojom/base/unguessable_token.mojom";
 import "url/mojom/url.mojom";
+import "third_party/blink/public/mojom/loader/transferrable_url_loader.mojom";
 import "third_party/blink/public/mojom/loader/url_loader_factory_bundle.mojom";
 import "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_container.mojom";
@@ -61,7 +61,7 @@
       handle<data_pipe_consumer>? response_body,
       network.mojom.URLLoaderClientEndpoints? url_loader_client_endpoints,
       blink.mojom.URLLoaderFactoryBundle? subresource_loader_factories,
-      array<TransferrableURLLoader>? subresource_overrides,
+      array<blink.mojom.TransferrableURLLoader>? subresource_overrides,
       blink.mojom.ControllerServiceWorkerInfo? controller_service_worker_info,
       blink.mojom.ServiceWorkerContainerInfoForClient? container_info,
       pending_remote<network.mojom.URLLoaderFactory>? prefetch_loader_factory,
diff --git a/content/common/service_worker/service_worker_utils.cc b/content/common/service_worker/service_worker_utils.cc
index 11d45678..0de8e1b 100644
--- a/content/common/service_worker/service_worker_utils.cc
+++ b/content/common/service_worker/service_worker_utils.cc
@@ -13,11 +13,8 @@
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/origin_util.h"
-#include "net/base/io_buffer.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_byte_range.h"
-#include "net/http/http_util.h"
-#include "net/url_request/url_request.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "third_party/blink/public/common/features.h"
@@ -248,51 +245,6 @@
   return ".Unknown";
 }
 
-ServiceWorkerUtils::ResourceResponseHeadAndMetadata::
-    ResourceResponseHeadAndMetadata(
-        network::mojom::URLResponseHeadPtr head,
-        scoped_refptr<net::IOBufferWithSize> metadata)
-    : head(std::move(head)), metadata(std::move(metadata)) {}
-
-ServiceWorkerUtils::ResourceResponseHeadAndMetadata::
-    ResourceResponseHeadAndMetadata(ResourceResponseHeadAndMetadata&& other) =
-        default;
-
-ServiceWorkerUtils::ResourceResponseHeadAndMetadata::
-    ~ResourceResponseHeadAndMetadata() = default;
-
-ServiceWorkerUtils::ResourceResponseHeadAndMetadata
-ServiceWorkerUtils::CreateResourceResponseHeadAndMetadata(
-    const net::HttpResponseInfo* http_info,
-    uint32_t options,
-    base::TimeTicks request_start_time,
-    base::TimeTicks response_start_time,
-    int response_data_size) {
-  DCHECK(http_info);
-  DCHECK(http_info->headers);
-
-  auto head = network::mojom::URLResponseHead::New();
-  head->request_start = request_start_time;
-  head->response_start = response_start_time;
-  head->request_time = http_info->request_time;
-  head->response_time = http_info->response_time;
-  head->headers = http_info->headers;
-  head->headers->GetMimeType(&head->mime_type);
-  head->headers->GetCharset(&head->charset);
-  head->content_length = response_data_size;
-  head->was_fetched_via_spdy = http_info->was_fetched_via_spdy;
-  head->was_alpn_negotiated = http_info->was_alpn_negotiated;
-  head->connection_info = http_info->connection_info;
-  head->alpn_negotiated_protocol = http_info->alpn_negotiated_protocol;
-  head->remote_endpoint = http_info->remote_endpoint;
-  head->cert_status = http_info->ssl_info.cert_status;
-
-  if (options & network::mojom::kURLLoadOptionSendSSLInfoWithResponse)
-    head->ssl_info = http_info->ssl_info;
-
-  return {std::move(head), std::move(http_info->metadata)};
-}
-
 bool LongestScopeMatcher::MatchLongest(const GURL& scope) {
   if (!ServiceWorkerUtils::ScopeMatches(scope, url_))
     return false;
diff --git a/content/common/service_worker/service_worker_utils.h b/content/common/service_worker/service_worker_utils.h
index 1ea5f93..33462720 100644
--- a/content/common/service_worker/service_worker_utils.h
+++ b/content/common/service_worker/service_worker_utils.h
@@ -14,8 +14,6 @@
 #include "base/macros.h"
 #include "content/common/content_export.h"
 #include "content/public/common/content_switches.h"
-#include "net/http/http_request_headers.h"
-#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "third_party/blink/public/common/fetch/fetch_api_request_headers_map.h"
 #include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom.h"
@@ -77,26 +75,6 @@
   CONTENT_EXPORT static const char* FetchResponseSourceToSuffix(
       network::mojom::FetchResponseSource source);
 
-  struct CONTENT_EXPORT ResourceResponseHeadAndMetadata {
-    ResourceResponseHeadAndMetadata(
-        network::mojom::URLResponseHeadPtr head,
-        scoped_refptr<net::IOBufferWithSize> metadata);
-    ResourceResponseHeadAndMetadata(ResourceResponseHeadAndMetadata&& other);
-    ResourceResponseHeadAndMetadata(
-        const ResourceResponseHeadAndMetadata& other) = delete;
-    ~ResourceResponseHeadAndMetadata();
-
-    network::mojom::URLResponseHeadPtr head;
-    scoped_refptr<net::IOBufferWithSize> metadata;
-  };
-
-  CONTENT_EXPORT static ResourceResponseHeadAndMetadata
-  CreateResourceResponseHeadAndMetadata(const net::HttpResponseInfo* http_info,
-                                        uint32_t options,
-                                        base::TimeTicks request_start_time,
-                                        base::TimeTicks response_start_time,
-                                        int response_data_size);
-
  private:
   static bool IsPathRestrictionSatisfiedInternal(
       const GURL& scope,
diff --git a/content/public/browser/navigation_handle.h b/content/public/browser/navigation_handle.h
index ec1ab7f4c..c679ff6 100644
--- a/content/public/browser/navigation_handle.h
+++ b/content/public/browser/navigation_handle.h
@@ -15,7 +15,6 @@
 #include "content/public/browser/restore_type.h"
 #include "content/public/common/impression.h"
 #include "content/public/common/referrer.h"
-#include "content/public/common/transferrable_url_loader.mojom.h"
 #include "net/base/auth.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/isolation_info.h"
@@ -23,6 +22,7 @@
 #include "net/dns/public/resolve_error_info.h"
 #include "net/http/http_response_info.h"
 #include "services/network/public/cpp/resource_request_body.h"
+#include "third_party/blink/public/mojom/loader/transferrable_url_loader.mojom.h"
 #include "ui/base/page_transition_types.h"
 
 class GURL;
@@ -382,7 +382,7 @@
   virtual int GetNavigationEntryOffset() = 0;
 
   virtual void RegisterSubresourceOverride(
-      mojom::TransferrableURLLoaderPtr transferrable_loader) = 0;
+      blink::mojom::TransferrableURLLoaderPtr transferrable_loader) = 0;
 
   // Force enables the given origin trials for this navigation. This needs to
   // be called from WebContents::ReadyToCommitNavigation or earlier to have an
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index 22651bb1..f1446d90 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -313,7 +313,6 @@
     "fullscreen_video_element.mojom",
     "performance_manager/v8_per_frame_memory.mojom",
     "resource_usage_reporter.mojom",
-    "transferrable_url_loader.mojom",
     "was_activated_option.mojom",
     "webplugininfo.mojom",
     "window_container_type.mojom",
diff --git a/content/public/test/mock_navigation_handle.h b/content/public/test/mock_navigation_handle.h
index c132ce6..7149f13 100644
--- a/content/public/test/mock_navigation_handle.h
+++ b/content/public/test/mock_navigation_handle.h
@@ -122,7 +122,7 @@
                void(std::unique_ptr<NavigationThrottle>));
   MOCK_METHOD0(IsDeferredForTesting, bool());
   MOCK_METHOD1(RegisterSubresourceOverride,
-               void(mojom::TransferrableURLLoaderPtr));
+               void(blink::mojom::TransferrableURLLoaderPtr));
   MOCK_METHOD0(FromDownloadCrossOriginRedirect, bool());
   MOCK_METHOD0(IsSameProcess, bool());
   MOCK_METHOD0(GetNavigationEntryOffset, int());
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc
index 1c5ae04..c5703be 100644
--- a/content/renderer/accessibility/blink_ax_tree_source.cc
+++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -810,7 +810,7 @@
     dst->SetListStyle(src.GetListStyle());
   }
 
-  if (src.GetTextDirection() != ax::mojom::TextDirection::kNone) {
+  if (src.GetTextDirection() != ax::mojom::WritingDirection::kNone) {
     dst->SetTextDirection(src.GetTextDirection());
   }
 
diff --git a/content/renderer/loader/child_url_loader_factory_bundle.cc b/content/renderer/loader/child_url_loader_factory_bundle.cc
index ed1ce72..c3ecec1 100644
--- a/content/renderer/loader/child_url_loader_factory_bundle.cc
+++ b/content/renderer/loader/child_url_loader_factory_bundle.cc
@@ -262,7 +262,7 @@
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
   auto override_iter = subresource_overrides_.find(request.url);
   if (override_iter != subresource_overrides_.end()) {
-    mojom::TransferrableURLLoaderPtr transferrable_loader =
+    blink::mojom::TransferrableURLLoaderPtr transferrable_loader =
         std::move(override_iter->second);
     subresource_overrides_.erase(override_iter);
 
@@ -325,7 +325,8 @@
 }
 
 void ChildURLLoaderFactoryBundle::UpdateSubresourceOverrides(
-    std::vector<mojom::TransferrableURLLoaderPtr>* subresource_overrides) {
+    std::vector<blink::mojom::TransferrableURLLoaderPtr>*
+        subresource_overrides) {
   for (auto& element : *subresource_overrides)
     subresource_overrides_[element->url] = std::move(element);
 }
diff --git a/content/renderer/loader/child_url_loader_factory_bundle.h b/content/renderer/loader/child_url_loader_factory_bundle.h
index 91b35704..880c826 100644
--- a/content/renderer/loader/child_url_loader_factory_bundle.h
+++ b/content/renderer/loader/child_url_loader_factory_bundle.h
@@ -12,12 +12,12 @@
 #include "base/callback.h"
 #include "base/optional.h"
 #include "content/common/content_export.h"
-#include "content/public/common/transferrable_url_loader.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "services/network/public/mojom/url_loader_factory.mojom-forward.h"
 #include "third_party/blink/public/common/loader/url_loader_factory_bundle.h"
+#include "third_party/blink/public/mojom/loader/transferrable_url_loader.mojom.h"
 
 namespace content {
 
@@ -121,7 +121,8 @@
   void Update(
       std::unique_ptr<ChildPendingURLLoaderFactoryBundle> pending_factories);
   void UpdateSubresourceOverrides(
-      std::vector<mojom::TransferrableURLLoaderPtr>* subresource_overrides);
+      std::vector<blink::mojom::TransferrableURLLoaderPtr>*
+          subresource_overrides);
   void SetPrefetchLoaderFactory(
       mojo::PendingRemote<network::mojom::URLLoaderFactory>
           prefetch_loader_factory);
@@ -150,7 +151,8 @@
 
   bool is_deprecated_process_wide_factory_ = false;
 
-  std::map<GURL, mojom::TransferrableURLLoaderPtr> subresource_overrides_;
+  std::map<GURL, blink::mojom::TransferrableURLLoaderPtr>
+      subresource_overrides_;
 };
 
 }  // namespace content
diff --git a/content/renderer/media/audio/audio_device_factory.cc b/content/renderer/media/audio/audio_device_factory.cc
index 8b210159..848ac33 100644
--- a/content/renderer/media/audio/audio_device_factory.cc
+++ b/content/renderer/media/audio/audio_device_factory.cc
@@ -16,7 +16,6 @@
 #include "base/threading/platform_thread.h"
 #include "build/build_config.h"
 #include "content/common/content_constants_internal.h"
-#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
 #include "content/renderer/media/audio/audio_input_ipc_factory.h"
 #include "content/renderer/media/audio/audio_output_ipc_factory.h"
 #include "content/renderer/media/audio/audio_renderer_mixer_manager.h"
@@ -28,6 +27,7 @@
 #include "media/audio/audio_output_device.h"
 #include "media/base/audio_renderer_mixer_input.h"
 #include "media/base/media_switches.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
 
 namespace content {
 
diff --git a/content/renderer/media/audio/audio_input_ipc_factory.cc b/content/renderer/media/audio/audio_input_ipc_factory.cc
index 3886a0cc..bc833be0 100644
--- a/content/renderer/media/audio/audio_input_ipc_factory.cc
+++ b/content/renderer/media/audio/audio_input_ipc_factory.cc
@@ -11,12 +11,12 @@
 #include "base/check_op.h"
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
-#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
 #include "content/renderer/media/audio/mojo_audio_input_ipc.h"
 #include "content/renderer/render_frame_impl.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
 
 namespace content {
 
@@ -25,7 +25,8 @@
 void CreateMojoAudioInputStreamOnMainThread(
     const base::UnguessableToken& frame_token,
     const media::AudioSourceParameters& source_params,
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client,
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+        client,
     const media::AudioParameters& params,
     bool automatic_gain_control,
     uint32_t total_segments) {
@@ -42,7 +43,8 @@
     scoped_refptr<base::SequencedTaskRunner> main_task_runner,
     const base::UnguessableToken& frame_token,
     const media::AudioSourceParameters& source_params,
-    mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client,
+    mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+        client,
     const media::AudioParameters& params,
     bool automatic_gain_control,
     uint32_t total_segments) {
diff --git a/content/renderer/media/audio/audio_output_ipc_factory.cc b/content/renderer/media/audio/audio_output_ipc_factory.cc
index 92dd24e..6651543 100644
--- a/content/renderer/media/audio/audio_output_ipc_factory.cc
+++ b/content/renderer/media/audio/audio_output_ipc_factory.cc
@@ -43,7 +43,8 @@
 void AudioOutputIPCFactory::RegisterRemoteFactory(
     const base::UnguessableToken& frame_token,
     blink::BrowserInterfaceBrokerProxy* interface_broker) {
-  mojo::PendingRemote<mojom::RendererAudioOutputStreamFactory> factory_remote;
+  mojo::PendingRemote<blink::mojom::RendererAudioOutputStreamFactory>
+      factory_remote;
   interface_broker->GetInterface(
       factory_remote.InitWithNewPipeAndPassReceiver());
   // Unretained is safe due to the contract at the top of the header file.
@@ -64,7 +65,7 @@
           base::Unretained(this), frame_token));
 }
 
-mojom::RendererAudioOutputStreamFactory*
+blink::mojom::RendererAudioOutputStreamFactory*
 AudioOutputIPCFactory::GetRemoteFactory(
     const base::UnguessableToken& frame_token) const {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
@@ -74,7 +75,7 @@
 
 void AudioOutputIPCFactory::RegisterRemoteFactoryOnIOThread(
     const base::UnguessableToken& frame_token,
-    mojo::PendingRemote<mojom::RendererAudioOutputStreamFactory>
+    mojo::PendingRemote<blink::mojom::RendererAudioOutputStreamFactory>
         factory_pending_remote) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   std::pair<StreamFactoryMap::iterator, bool> emplace_result =
diff --git a/content/renderer/media/audio/audio_output_ipc_factory.h b/content/renderer/media/audio/audio_output_ipc_factory.h
index b8a5171..d950e66e 100644
--- a/content/renderer/media/audio/audio_output_ipc_factory.h
+++ b/content/renderer/media/audio/audio_output_ipc_factory.h
@@ -10,9 +10,9 @@
 #include "base/containers/flat_map.h"
 #include "base/memory/ref_counted.h"
 #include "content/common/content_export.h"
-#include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_output_stream_factory.mojom.h"
 
 namespace base {
 class SingleThreadTaskRunner;
@@ -64,16 +64,16 @@
       const base::UnguessableToken& frame_token) const;
 
  private:
-  using StreamFactoryMap =
-      base::flat_map<base::UnguessableToken,
-                     mojo::Remote<mojom::RendererAudioOutputStreamFactory>>;
+  using StreamFactoryMap = base::flat_map<
+      base::UnguessableToken,
+      mojo::Remote<blink::mojom::RendererAudioOutputStreamFactory>>;
 
-  mojom::RendererAudioOutputStreamFactory* GetRemoteFactory(
+  blink::mojom::RendererAudioOutputStreamFactory* GetRemoteFactory(
       const base::UnguessableToken& frame_token) const;
 
   void RegisterRemoteFactoryOnIOThread(
       const base::UnguessableToken& frame_token,
-      mojo::PendingRemote<mojom::RendererAudioOutputStreamFactory>
+      mojo::PendingRemote<blink::mojom::RendererAudioOutputStreamFactory>
           factory_pending_remote);
 
   void MaybeDeregisterRemoteFactoryOnIOThread(
diff --git a/content/renderer/media/audio/audio_output_ipc_factory_unittest.cc b/content/renderer/media/audio/audio_output_ipc_factory_unittest.cc
index 03a2e92b..24514c3c 100644
--- a/content/renderer/media/audio/audio_output_ipc_factory_unittest.cc
+++ b/content/renderer/media/audio/audio_output_ipc_factory_unittest.cc
@@ -44,7 +44,8 @@
   return io_thread;
 }
 
-class FakeRemoteFactory : public mojom::RendererAudioOutputStreamFactory {
+class FakeRemoteFactory
+    : public blink::mojom::RendererAudioOutputStreamFactory {
  public:
   FakeRemoteFactory() = default;
   ~FakeRemoteFactory() override {}
@@ -69,12 +70,13 @@
   void Bind(mojo::ScopedMessagePipeHandle handle) {
     EXPECT_FALSE(receiver_.is_bound());
     receiver_.Bind(
-        mojo::PendingReceiver<mojom::RendererAudioOutputStreamFactory>(
+        mojo::PendingReceiver<blink::mojom::RendererAudioOutputStreamFactory>(
             std::move(handle)));
   }
 
  private:
-  mojo::Receiver<mojom::RendererAudioOutputStreamFactory> receiver_{this};
+  mojo::Receiver<blink::mojom::RendererAudioOutputStreamFactory> receiver_{
+      this};
   base::OnceClosure on_called_;
 };
 
@@ -120,7 +122,7 @@
 
   auto& interface_broker = blink::GetEmptyBrowserInterfaceBroker();
   interface_broker.SetBinderForTesting(
-      mojom::RendererAudioOutputStreamFactory::Name_,
+      blink::mojom::RendererAudioOutputStreamFactory::Name_,
       base::BindRepeating(&FakeRemoteFactory::Bind,
                           base::Unretained(&remote_factory)));
 
@@ -146,7 +148,7 @@
   ipc_factory.MaybeDeregisterRemoteFactory(TokenFromInt(0));
 
   interface_broker.SetBinderForTesting(
-      mojom::RendererAudioOutputStreamFactory::Name_, {});
+      blink::mojom::RendererAudioOutputStreamFactory::Name_, {});
 
   io_thread.reset();
   base::RunLoop().RunUntilIdle();
@@ -163,7 +165,7 @@
   auto& interface_broker = blink::GetEmptyBrowserInterfaceBroker();
 
   interface_broker.SetBinderForTesting(
-      mojom::RendererAudioOutputStreamFactory::Name_,
+      blink::mojom::RendererAudioOutputStreamFactory::Name_,
       base::BindLambdaForTesting([&](mojo::ScopedMessagePipeHandle handle) {
         static int factory_index = 0;
         DCHECK_LT(factory_index, n_factories);
@@ -209,7 +211,7 @@
   }
 
   interface_broker.SetBinderForTesting(
-      mojom::RendererAudioOutputStreamFactory::Name_, {});
+      blink::mojom::RendererAudioOutputStreamFactory::Name_, {});
 
   io_thread.reset();
   base::RunLoop().RunUntilIdle();
@@ -225,7 +227,7 @@
 
   auto& interface_broker = blink::GetEmptyBrowserInterfaceBroker();
   interface_broker.SetBinderForTesting(
-      mojom::RendererAudioOutputStreamFactory::Name_,
+      blink::mojom::RendererAudioOutputStreamFactory::Name_,
       base::BindRepeating(&FakeRemoteFactory::Bind,
                           base::Unretained(&remote_factory)));
 
@@ -240,7 +242,7 @@
   base::RunLoop().RunUntilIdle();
 
   interface_broker.SetBinderForTesting(
-      mojom::RendererAudioOutputStreamFactory::Name_, {});
+      blink::mojom::RendererAudioOutputStreamFactory::Name_, {});
   io_thread.reset();
   base::RunLoop().RunUntilIdle();
 }
diff --git a/content/renderer/media/audio/mojo_audio_input_ipc.cc b/content/renderer/media/audio/mojo_audio_input_ipc.cc
index 450acb41..519a6099 100644
--- a/content/renderer/media/audio/mojo_audio_input_ipc.cc
+++ b/content/renderer/media/audio/mojo_audio_input_ipc.cc
@@ -39,7 +39,8 @@
 
   delegate_ = delegate;
 
-  mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client;
+  mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+      client;
   factory_client_receiver_.Bind(client.InitWithNewPipeAndPassReceiver());
   factory_client_receiver_.set_disconnect_handler(base::BindOnce(
       &media::AudioInputIPCDelegate::OnError, base::Unretained(delegate_)));
diff --git a/content/renderer/media/audio/mojo_audio_input_ipc.h b/content/renderer/media/audio/mojo_audio_input_ipc.h
index 58efe08..032cc06f 100644
--- a/content/renderer/media/audio/mojo_audio_input_ipc.h
+++ b/content/renderer/media/audio/mojo_audio_input_ipc.h
@@ -13,7 +13,6 @@
 #include "base/sequence_checker.h"
 #include "base/time/time.h"
 #include "content/common/content_export.h"
-#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
 #include "media/audio/audio_input_ipc.h"
 #include "media/audio/audio_source_parameters.h"
 #include "media/mojo/mojom/audio_input_stream.mojom.h"
@@ -22,6 +21,7 @@
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
 
 namespace content {
 
@@ -30,7 +30,7 @@
 // thread.
 class CONTENT_EXPORT MojoAudioInputIPC
     : public media::AudioInputIPC,
-      public mojom::RendererAudioInputStreamFactoryClient,
+      public blink::mojom::RendererAudioInputStreamFactoryClient,
       public media::mojom::AudioInputStreamClient {
  public:
   // This callback is used by MojoAudioInputIPC to create streams.
@@ -38,7 +38,8 @@
   // called or |client| is destructed.
   using StreamCreatorCB = base::RepeatingCallback<void(
       const media::AudioSourceParameters& source_params,
-      mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient> client,
+      mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+          client,
       const media::AudioParameters& params,
       bool automatic_gain_control,
       uint32_t total_segments)>;
@@ -85,7 +86,7 @@
   // Initialized on StreamCreated.
   base::Optional<base::UnguessableToken> stream_id_;
   mojo::Receiver<AudioInputStreamClient> stream_client_receiver_{this};
-  mojo::Receiver<RendererAudioInputStreamFactoryClient>
+  mojo::Receiver<blink::mojom::RendererAudioInputStreamFactoryClient>
       factory_client_receiver_{this};
   media::AudioInputIPCDelegate* delegate_ = nullptr;
 
diff --git a/content/renderer/media/audio/mojo_audio_input_ipc_unittest.cc b/content/renderer/media/audio/mojo_audio_input_ipc_unittest.cc
index 22681946..6dc7264 100644
--- a/content/renderer/media/audio/mojo_audio_input_ipc_unittest.cc
+++ b/content/renderer/media/audio/mojo_audio_input_ipc_unittest.cc
@@ -82,12 +82,13 @@
         receiver_(stream_),
         initially_muted_(initially_muted) {}
 
-  void Create(const media::AudioSourceParameters& source_params,
-              mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
-                  factory_client,
-              const media::AudioParameters& params,
-              bool automatic_gain_control,
-              uint32_t total_segments) {
+  void Create(
+      const media::AudioSourceParameters& source_params,
+      mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+          factory_client,
+      const media::AudioParameters& params,
+      bool automatic_gain_control,
+      uint32_t total_segments) {
     EXPECT_FALSE(receiver_.is_bound());
     EXPECT_NE(stream_, nullptr);
     EXPECT_EQ(source_params.session_id, SourceParams().session_id);
@@ -124,7 +125,8 @@
  private:
   media::mojom::AudioInputStream* stream_;
   mojo::Remote<media::mojom::AudioInputStreamClient> stream_client_;
-  mojo::Remote<mojom::RendererAudioInputStreamFactoryClient> factory_client_;
+  mojo::Remote<blink::mojom::RendererAudioInputStreamFactoryClient>
+      factory_client_;
   mojo::Receiver<media::mojom::AudioInputStream> receiver_;
   bool initially_muted_;
   base::CancelableSyncSocket socket_;
@@ -164,16 +166,17 @@
       base::test::SingleThreadTaskEnvironment::MainThreadType::IO);
   StrictMock<MockDelegate> delegate;
 
-  const std::unique_ptr<media::AudioInputIPC> ipc = std::make_unique<
-      MojoAudioInputIPC>(
-      SourceParams(),
-      base::BindRepeating(
-          [](const media::AudioSourceParameters&,
-             mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
-                 factory_client,
-             const media::AudioParameters& params, bool automatic_gain_control,
-             uint32_t total_segments) {}),
-      base::BindRepeating(&AssociateOutputForAec));
+  const std::unique_ptr<media::AudioInputIPC> ipc =
+      std::make_unique<MojoAudioInputIPC>(
+          SourceParams(),
+          base::BindRepeating(
+              [](const media::AudioSourceParameters&,
+                 mojo::PendingRemote<
+                     blink::mojom::RendererAudioInputStreamFactoryClient>
+                     factory_client,
+                 const media::AudioParameters& params,
+                 bool automatic_gain_control, uint32_t total_segments) {}),
+          base::BindRepeating(&AssociateOutputForAec));
 
   EXPECT_CALL(delegate, OnError());
 
diff --git a/content/renderer/media/audio/mojo_audio_output_ipc.h b/content/renderer/media/audio/mojo_audio_output_ipc.h
index 52fb420b..e4295b74 100644
--- a/content/renderer/media/audio/mojo_audio_output_ipc.h
+++ b/content/renderer/media/audio/mojo_audio_output_ipc.h
@@ -14,7 +14,6 @@
 #include "base/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "content/common/content_export.h"
-#include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
 #include "media/audio/audio_output_ipc.h"
 #include "media/mojo/mojom/audio_data_pipe.mojom.h"
 #include "media/mojo/mojom/audio_output_stream.mojom.h"
@@ -22,6 +21,7 @@
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_output_stream_factory.mojom.h"
 
 namespace content {
 
@@ -32,8 +32,8 @@
     : public media::AudioOutputIPC,
       public media::mojom::AudioOutputStreamProviderClient {
  public:
-  using FactoryAccessorCB =
-      base::RepeatingCallback<mojom::RendererAudioOutputStreamFactory*()>;
+  using FactoryAccessorCB = base::RepeatingCallback<
+      blink::mojom::RendererAudioOutputStreamFactory*()>;
 
   // |factory_accessor| is required to provide a
   // RendererAudioOutputStreamFactory* if IPC is possible.
@@ -64,7 +64,7 @@
  private:
   static constexpr double kDefaultVolume = 1.0;
 
-  using AuthorizationCB = mojom::RendererAudioOutputStreamFactory::
+  using AuthorizationCB = blink::mojom::RendererAudioOutputStreamFactory::
       RequestDeviceAuthorizationCallback;
 
   bool AuthorizationRequested() const;
diff --git a/content/renderer/media/audio/mojo_audio_output_ipc_unittest.cc b/content/renderer/media/audio/mojo_audio_output_ipc_unittest.cc
index 4c0824789..2aee416 100644
--- a/content/renderer/media/audio/mojo_audio_output_ipc_unittest.cc
+++ b/content/renderer/media/audio/mojo_audio_output_ipc_unittest.cc
@@ -46,7 +46,9 @@
 
 MojoAudioOutputIPC::FactoryAccessorCB NullAccessor() {
   return base::BindRepeating(
-      []() -> mojom::RendererAudioOutputStreamFactory* { return nullptr; });
+      []() -> blink::mojom::RendererAudioOutputStreamFactory* {
+        return nullptr;
+      });
 }
 
 class TestStreamProvider : public media::mojom::AudioOutputStreamProvider {
@@ -94,7 +96,8 @@
   base::CancelableSyncSocket socket_;
 };
 
-class TestRemoteFactory : public mojom::RendererAudioOutputStreamFactory {
+class TestRemoteFactory
+    : public blink::mojom::RendererAudioOutputStreamFactory {
  public:
   TestRemoteFactory()
       : expect_request_(false),
@@ -165,14 +168,17 @@
   }
 
  private:
-  mojom::RendererAudioOutputStreamFactory* get() { return this_remote_.get(); }
+  blink::mojom::RendererAudioOutputStreamFactory* get() {
+    return this_remote_.get();
+  }
 
   bool expect_request_;
   base::Optional<base::UnguessableToken> expected_session_id_;
   std::string expected_device_id_;
 
-  mojo::Remote<mojom::RendererAudioOutputStreamFactory> this_remote_;
-  mojo::Receiver<mojom::RendererAudioOutputStreamFactory> receiver_{this};
+  mojo::Remote<blink::mojom::RendererAudioOutputStreamFactory> this_remote_;
+  mojo::Receiver<blink::mojom::RendererAudioOutputStreamFactory> receiver_{
+      this};
   std::unique_ptr<TestStreamProvider> provider_;
   base::Optional<mojo::Receiver<media::mojom::AudioOutputStreamProvider>>
       provider_receiver_;
diff --git a/content/renderer/navigation_client.cc b/content/renderer/navigation_client.cc
index 0d9b602a..8252b91 100644
--- a/content/renderer/navigation_client.cc
+++ b/content/renderer/navigation_client.cc
@@ -22,7 +22,7 @@
     mojo::ScopedDataPipeConsumerHandle response_body,
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     std::unique_ptr<blink::PendingURLLoaderFactoryBundle> subresource_loaders,
-    base::Optional<std::vector<::content::mojom::TransferrableURLLoaderPtr>>
+    base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
         subresource_overrides,
     blink::mojom::ControllerServiceWorkerInfoPtr controller_service_worker_info,
     blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info,
diff --git a/content/renderer/navigation_client.h b/content/renderer/navigation_client.h
index 404d863b..7284e18 100644
--- a/content/renderer/navigation_client.h
+++ b/content/renderer/navigation_client.h
@@ -26,7 +26,7 @@
       mojo::ScopedDataPipeConsumerHandle response_body,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       std::unique_ptr<blink::PendingURLLoaderFactoryBundle> subresource_loaders,
-      base::Optional<std::vector<::content::mojom::TransferrableURLLoaderPtr>>
+      base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
           subresource_overrides,
       blink::mojom::ControllerServiceWorkerInfoPtr
           controller_service_worker_info,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 4b25d73..c571b07 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -3071,7 +3071,7 @@
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
         subresource_loader_factories,
-    base::Optional<std::vector<mojom::TransferrableURLLoaderPtr>>
+    base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
         subresource_overrides,
     blink::mojom::ControllerServiceWorkerInfoPtr controller_service_worker_info,
     blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info,
@@ -3206,7 +3206,7 @@
     mojom::CommitNavigationParamsPtr commit_params,
     std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
         subresource_loader_factories,
-    base::Optional<std::vector<mojom::TransferrableURLLoaderPtr>>
+    base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
         subresource_overrides,
     blink::mojom::ControllerServiceWorkerInfoPtr controller_service_worker_info,
     blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info,
@@ -3291,7 +3291,7 @@
     // The browser expects the frame to be loading this navigation. Inform it
     // that the load stopped if needed.
     if (frame_ && !frame_->IsLoading())
-      Send(new FrameHostMsg_DidStopLoading(routing_id_));
+      GetFrameHost()->DidStopLoading();
     return;
   }
 
@@ -3379,7 +3379,7 @@
     // The browser expects this frame to be loading an error page. Inform it
     // that the load stopped.
     AbortCommitNavigation();
-    Send(new FrameHostMsg_DidStopLoading(routing_id_));
+    GetFrameHost()->DidStopLoading();
     browser_side_navigation_pending_ = false;
     browser_side_navigation_pending_url_ = GURL();
     return;
@@ -3412,7 +3412,7 @@
       // either, as the frame has already been populated with something
       // unrelated to this navigation failure. In that case, just send a stop
       // IPC to the browser to unwind its state, and leave the frame as-is.
-      Send(new FrameHostMsg_DidStopLoading(routing_id_));
+      GetFrameHost()->DidStopLoading();
     }
     browser_side_navigation_pending_ = false;
     browser_side_navigation_pending_url_ = GURL();
@@ -3572,7 +3572,7 @@
   // that the load stopped if needed.
   if (frame_ && !frame_->IsLoading() &&
       commit_status != blink::mojom::CommitResult::Ok) {
-    Send(new FrameHostMsg_DidStopLoading(routing_id_));
+    GetFrameHost()->DidStopLoading();
   }
 }
 
@@ -3591,7 +3591,7 @@
   // that the load stopped if needed, while leaving the debug URL visible in the
   // address bar.
   if (weak_this && frame_ && !frame_->IsLoading())
-    Send(new FrameHostMsg_DidStopLoading(routing_id_));
+    GetFrameHost()->DidStopLoading();
 }
 
 void RenderFrameImpl::UpdateSubresourceLoaderFactories(
@@ -4862,7 +4862,7 @@
   return WebString();
 }
 
-mojom::RendererAudioInputStreamFactory*
+blink::mojom::RendererAudioInputStreamFactory*
 RenderFrameImpl::GetAudioInputStreamFactory() {
   if (!audio_input_stream_factory_)
     GetBrowserInterfaceBroker()->GetInterface(
@@ -5400,7 +5400,7 @@
   // this state anymore.
   history_subframe_unique_names_.clear();
 
-  Send(new FrameHostMsg_DidStopLoading(routing_id_));
+  GetFrameHost()->DidStopLoading();
 }
 
 void RenderFrameImpl::NotifyAccessibilityModeChange(ui::AXMode new_mode) {
@@ -5809,7 +5809,7 @@
 scoped_refptr<ChildURLLoaderFactoryBundle>
 RenderFrameImpl::CreateLoaderFactoryBundle(
     std::unique_ptr<blink::PendingURLLoaderFactoryBundle> info,
-    base::Optional<std::vector<mojom::TransferrableURLLoaderPtr>>
+    base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
         subresource_overrides,
     mojo::PendingRemote<network::mojom::URLLoaderFactory>
         prefetch_loader_factory) {
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index c5b50c3..e3b965a 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -34,7 +34,6 @@
 #include "content/common/download/mhtml_file_writer.mojom.h"
 #include "content/common/frame.mojom.h"
 #include "content/common/frame_delete_intention.h"
-#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
 #include "content/common/navigation_params.mojom.h"
 #include "content/common/render_accessibility.mojom.h"
 #include "content/common/renderer.mojom.h"
@@ -92,6 +91,7 @@
 #include "third_party/blink/public/mojom/input/focus_type.mojom-forward.h"
 #include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h"
 #include "third_party/blink/public/mojom/loader/resource_load_info_notifier.mojom.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
 #include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
 #include "third_party/blink/public/mojom/use_counter/css_property_id.mojom.h"
@@ -553,7 +553,7 @@
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
           subresource_loader_factories,
-      base::Optional<std::vector<mojom::TransferrableURLLoaderPtr>>
+      base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
           subresource_overrides,
       blink::mojom::ControllerServiceWorkerInfoPtr
           controller_service_worker_info,
@@ -745,7 +745,7 @@
   blink::WebString UserAgentOverride() override;
   base::Optional<blink::UserAgentMetadata> UserAgentMetadataOverride() override;
   blink::WebString DoNotTrackValue() override;
-  mojom::RendererAudioInputStreamFactory* GetAudioInputStreamFactory();
+  blink::mojom::RendererAudioInputStreamFactory* GetAudioInputStreamFactory();
   bool AllowContentInitiatedDataUrlNavigations(
       const blink::WebURL& url) override;
   void PostAccessibilityEvent(const ui::AXEvent& event) override;
@@ -1039,7 +1039,7 @@
 
   scoped_refptr<ChildURLLoaderFactoryBundle> CreateLoaderFactoryBundle(
       std::unique_ptr<blink::PendingURLLoaderFactoryBundle> info,
-      base::Optional<std::vector<mojom::TransferrableURLLoaderPtr>>
+      base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
           subresource_overrides,
       mojo::PendingRemote<network::mojom::URLLoaderFactory>
           prefetch_loader_factory);
@@ -1086,7 +1086,7 @@
       mojom::CommitNavigationParamsPtr commit_params,
       std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
           subresource_loader_factories,
-      base::Optional<std::vector<mojom::TransferrableURLLoaderPtr>>
+      base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
           subresource_overrides,
       blink::mojom::ControllerServiceWorkerInfoPtr
           controller_service_worker_info,
@@ -1364,7 +1364,7 @@
   std::unique_ptr<blink::WebMediaStreamDeviceObserver>
       web_media_stream_device_observer_;
 
-  mojo::Remote<mojom::RendererAudioInputStreamFactory>
+  mojo::Remote<blink::mojom::RendererAudioInputStreamFactory>
       audio_input_stream_factory_;
 
   // The media permission dispatcher attached to this frame.
diff --git a/content/shell/renderer/web_test/web_ax_object_proxy.cc b/content/shell/renderer/web_test/web_ax_object_proxy.cc
index 8aeecdc..1cc6896 100644
--- a/content/shell/renderer/web_test/web_ax_object_proxy.cc
+++ b/content/shell/renderer/web_test/web_ax_object_proxy.cc
@@ -470,7 +470,7 @@
       return blink::WebRect();
 
     switch (inline_text_box.GetTextDirection()) {
-      case ax::mojom::TextDirection::kLtr: {
+      case ax::mojom::WritingDirection::kLtr: {
         if (local_index) {
           int left =
               inline_text_box_rect.x + character_offsets[local_index - 1];
@@ -483,7 +483,7 @@
                               character_offsets[0],
                               inline_text_box_rect.height);
       }
-      case ax::mojom::TextDirection::kRtl: {
+      case ax::mojom::WritingDirection::kRtl: {
         int right = inline_text_box_rect.x + inline_text_box_rect.width;
 
         if (local_index) {
@@ -498,7 +498,7 @@
                               character_offsets[0],
                               inline_text_box_rect.height);
       }
-      case ax::mojom::TextDirection::kTtb: {
+      case ax::mojom::WritingDirection::kTtb: {
         if (local_index) {
           int top = inline_text_box_rect.y + character_offsets[local_index - 1];
           int height = character_offsets[local_index] -
@@ -509,7 +509,7 @@
         return blink::WebRect(inline_text_box_rect.x, inline_text_box_rect.y,
                               inline_text_box_rect.width, character_offsets[0]);
       }
-      case ax::mojom::TextDirection::kBtt: {
+      case ax::mojom::WritingDirection::kBtt: {
         int bottom = inline_text_box_rect.y + inline_text_box_rect.height;
 
         if (local_index) {
diff --git a/content/test/test_render_frame.cc b/content/test/test_render_frame.cc
index 695d8c8..f09faaf 100644
--- a/content/test/test_render_frame.cc
+++ b/content/test/test_render_frame.cc
@@ -217,6 +217,8 @@
     is_url_opened_ = true;
   }
 
+  void DidStopLoading() override {}
+
   void DidAddMessageToConsole(blink::mojom::ConsoleMessageLevel log_level,
                               const base::string16& msg,
                               int32_t line_number,
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index 19706d6..7cd67ba 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -548,7 +548,7 @@
     network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
         subresource_loader_factories,
-    base::Optional<std::vector<::content::mojom::TransferrableURLLoaderPtr>>
+    base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
         subresource_overrides,
     blink::mojom::ControllerServiceWorkerInfoPtr controller,
     blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info,
@@ -695,7 +695,7 @@
     DidFinishLoad(GetLastCommittedURL());
   }
 
-  OnDidStopLoading();
+  DidStopLoading();
 }
 
 }  // namespace content
diff --git a/content/test/test_render_frame_host.h b/content/test/test_render_frame_host.h
index d23cdeec..57d6178 100644
--- a/content/test/test_render_frame_host.h
+++ b/content/test/test_render_frame_host.h
@@ -224,7 +224,7 @@
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
           subresource_loader_factories,
-      base::Optional<std::vector<::content::mojom::TransferrableURLLoaderPtr>>
+      base::Optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
           subresource_overrides,
       blink::mojom::ControllerServiceWorkerInfoPtr
           controller_service_worker_info,
diff --git a/docs/android_build_instructions.md b/docs/android_build_instructions.md
index 8cad7fc6..cc36d85 100644
--- a/docs/android_build_instructions.md
+++ b/docs/android_build_instructions.md
@@ -355,6 +355,17 @@
    * What it does: Uses multiple `.so` files instead of just one (faster links)
  * `is_java_debug = true` *(default=`is_debug`)*
    * What it does: Disables ProGuard (slow build step)
+ * `treat_warnings_as_errors = false` *(default=`true`)*
+   * Causes any compiler warnings or lint checks to not fail the build.
+   * Allows you to iterate without needing to satisfy static analysis checks.
+ * `use_errorprone_java_compiler = false` *(default=`true`)
+   * Don't run Errorprone checks when compiling Java files.
+   * Speeds up Java compiles by ~30% at the cost of not seeing ErrorProne
+     warnings.
+ * `disable_android_lint = true` *(default=`false`)*
+   * Don't run Android Lint when building APK / App Bundle targets.
+   * Lint usually takes > 60 seconds to run, so disabling it dramatically
+     reduces incremental build times.
 
 #### Incremental Install
 [Incremental Install](/build/android/incremental_install/README.md) uses
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index 0d6fb4b0..72dd41b 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -268,6 +268,7 @@
     "info_map.cc",
     "info_map.h",
     "install_flag.h",
+    "install_stage.h",
     "json_file_sanitizer.cc",
     "json_file_sanitizer.h",
     "lazy_background_task_queue.cc",
diff --git a/extensions/browser/guest_view/extensions_guest_view_message_filter.cc b/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
index 7c442c9b..9478fd08 100644
--- a/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
+++ b/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
@@ -202,7 +202,7 @@
     const GURL& original_url,
     int32_t element_instance_id,
     const gfx::Size& element_size,
-    content::mojom::TransferrableURLLoaderPtr transferrable_url_loader) {
+    blink::mojom::TransferrableURLLoaderPtr transferrable_url_loader) {
   if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
     content::GetUIThreadTaskRunner({})->PostTask(
         FROM_HERE, base::BindOnce(&ExtensionsGuestViewMessageFilter::
diff --git a/extensions/browser/guest_view/extensions_guest_view_message_filter.h b/extensions/browser/guest_view/extensions_guest_view_message_filter.h
index fc9ce56..69ef8643 100644
--- a/extensions/browser/guest_view/extensions_guest_view_message_filter.h
+++ b/extensions/browser/guest_view/extensions_guest_view_message_filter.h
@@ -75,7 +75,7 @@
       const GURL& original_url,
       int32_t element_instance_id,
       const gfx::Size& element_size,
-      content::mojom::TransferrableURLLoaderPtr transferrable_url_loader)
+      blink::mojom::TransferrableURLLoaderPtr transferrable_url_loader)
       override;
   void CreateMimeHandlerViewGuest(
       int32_t render_frame_id,
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
index 390b07fc..d5ccc45 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
@@ -46,7 +46,7 @@
     bool embedded,
     const GURL& handler_url,
     const std::string& extension_id,
-    content::mojom::TransferrableURLLoaderPtr transferrable_loader,
+    blink::mojom::TransferrableURLLoaderPtr transferrable_loader,
     const GURL& original_url)
     : embedded_(embedded),
       tab_id_(tab_id),
@@ -65,7 +65,7 @@
   return weak_factory_.GetWeakPtr();
 }
 
-content::mojom::TransferrableURLLoaderPtr
+blink::mojom::TransferrableURLLoaderPtr
 StreamContainer::TakeTransferrableURLLoader() {
   return std::move(transferrable_loader_);
 }
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
index 56babf6..3e287fd 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
@@ -11,10 +11,10 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "components/guest_view/browser/guest_view.h"
-#include "content/public/common/transferrable_url_loader.mojom.h"
 #include "extensions/common/api/mime_handler.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
+#include "third_party/blink/public/mojom/loader/transferrable_url_loader.mojom.h"
 
 namespace content {
 class WebContents;
@@ -28,18 +28,17 @@
 // resource stream.
 class StreamContainer {
  public:
-  StreamContainer(
-      int tab_id,
-      bool embedded,
-      const GURL& handler_url,
-      const std::string& extension_id,
-      content::mojom::TransferrableURLLoaderPtr transferrable_loader,
-      const GURL& original_url);
+  StreamContainer(int tab_id,
+                  bool embedded,
+                  const GURL& handler_url,
+                  const std::string& extension_id,
+                  blink::mojom::TransferrableURLLoaderPtr transferrable_loader,
+                  const GURL& original_url);
   ~StreamContainer();
 
   base::WeakPtr<StreamContainer> GetWeakPtr();
 
-  content::mojom::TransferrableURLLoaderPtr TakeTransferrableURLLoader();
+  blink::mojom::TransferrableURLLoaderPtr TakeTransferrableURLLoader();
 
   bool embedded() const { return embedded_; }
   int tab_id() const { return tab_id_; }
@@ -58,7 +57,7 @@
   const int tab_id_;
   const GURL handler_url_;
   const std::string extension_id_;
-  content::mojom::TransferrableURLLoaderPtr transferrable_loader_;
+  blink::mojom::TransferrableURLLoaderPtr transferrable_loader_;
 
   std::string mime_type_;
   GURL original_url_;
diff --git a/extensions/browser/install_stage.h b/extensions/browser/install_stage.h
new file mode 100644
index 0000000..b4d0a375
--- /dev/null
+++ b/extensions/browser/install_stage.h
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_INSTALL_STAGE_H_
+#define EXTENSIONS_BROWSER_INSTALL_STAGE_H_
+
+namespace extensions {
+
+// The different stages of the extension installation process.
+enum class InstallationStage {
+  // The validation of signature of the extensions is about to be started.
+  kVerification = 0,
+  // Extension archive is about to be copied into the working directory.
+  kCopying = 1,
+  // Extension archive is about to be unpacked.
+  kUnpacking = 2,
+  // Final checks before the installation is finished.
+  kFinalizing = 3,
+  kComplete = 4,
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_INSTALL_STAGE_H_
diff --git a/extensions/browser/sandboxed_unpacker.cc b/extensions/browser/sandboxed_unpacker.cc
index 783d7b87..2c25b11 100644
--- a/extensions/browser/sandboxed_unpacker.cc
+++ b/extensions/browser/sandboxed_unpacker.cc
@@ -34,6 +34,7 @@
 #include "extensions/browser/extension_file_task_runner.h"
 #include "extensions/browser/install/crx_install_error.h"
 #include "extensions/browser/install/sandboxed_unpacker_failure_reason.h"
+#include "extensions/browser/install_stage.h"
 #include "extensions/browser/zipfile_installer.h"
 #include "extensions/common/api/declarative_net_request/dnr_manifest_data.h"
 #include "extensions/common/constants.h"
@@ -222,7 +223,7 @@
   // We assume that we are started on the thread that the client wants us
   // to do file IO on.
   DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
-
+  client_->OnStageChanged(InstallationStage::kVerification);
   std::string expected_hash;
   if (!crx_info.expected_hash.empty() &&
       base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -242,6 +243,7 @@
                              crx_info.required_format)))
     return;  // ValidateSignature() already reported the error.
 
+  client_->OnStageChanged(InstallationStage::kCopying);
   // Copy the crx file into our working directory.
   base::FilePath temp_crx_path =
       temp_dir_.GetPath().Append(crx_info.path.BaseName());
@@ -271,7 +273,7 @@
         l10n_util::GetStringUTF16(IDS_EXTENSION_UNPACK_FAILED));
     return;
   }
-
+  client_->OnStageChanged(InstallationStage::kUnpacking);
   // Make sure to create the directory where the extension will be unzipped, as
   // the unzipper service requires it.
   base::FilePath unzipped_dir =
diff --git a/extensions/browser/sandboxed_unpacker.h b/extensions/browser/sandboxed_unpacker.h
index f9b702c..cf83572 100644
--- a/extensions/browser/sandboxed_unpacker.h
+++ b/extensions/browser/sandboxed_unpacker.h
@@ -41,6 +41,7 @@
 namespace extensions {
 class Extension;
 enum class SandboxedUnpackerFailureReason;
+enum class InstallationStage;
 
 namespace declarative_net_request {
 struct IndexAndPersistJSONRulesetResult;
@@ -88,6 +89,9 @@
       declarative_net_request::RulesetChecksums ruleset_checksums) = 0;
   virtual void OnUnpackFailure(const CrxInstallError& error) = 0;
 
+  // Called after stage of installation is changed.
+  virtual void OnStageChanged(InstallationStage stage) {}
+
  protected:
   friend class base::RefCountedDeleteOnSequence<SandboxedUnpackerClient>;
   friend class base::DeleteHelper<SandboxedUnpackerClient>;
diff --git a/extensions/common/mojom/guest_view.mojom b/extensions/common/mojom/guest_view.mojom
index 52a1aafb..7b637367 100644
--- a/extensions/common/mojom/guest_view.mojom
+++ b/extensions/common/mojom/guest_view.mojom
@@ -4,8 +4,8 @@
 
 module extensions.mojom;
 
-import "content/public/common/transferrable_url_loader.mojom";
 import "extensions/common/api/mime_handler.mojom";
+import "third_party/blink/public/mojom/loader/transferrable_url_loader.mojom";
 import "ui/gfx/geometry/mojom/geometry.mojom";
 import "url/mojom/url.mojom";
 
@@ -19,7 +19,7 @@
       url.mojom.Url original_url,
       int32 element_instance_id,
       gfx.mojom.Size element_size,
-      content.mojom.TransferrableURLLoader transferrable_url_loader);
+      blink.mojom.TransferrableURLLoader transferrable_url_loader);
 
   // Tells the browser to create a mime handler guest view for a plugin.
   // This method is called for full-frame plugins or for all plugins when the
diff --git a/extensions/renderer/DEPS b/extensions/renderer/DEPS
index b4650051..53951d1 100644
--- a/extensions/renderer/DEPS
+++ b/extensions/renderer/DEPS
@@ -9,6 +9,7 @@
   "+third_party/cld_3",
 
   "+third_party/blink/public/mojom/devtools/console_message.mojom.h",
+  "+third_party/blink/public/mojom/loader/transferrable_url_loader.mojom.h",
   "+third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h",
   "+third_party/blink/public/platform",
   "+third_party/blink/public/strings/grit/blink_strings.h",
diff --git a/extensions/renderer/api/automation/automation_internal_custom_bindings.cc b/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
index 0fbbff6..e6453dc2 100644
--- a/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
+++ b/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
@@ -948,21 +948,21 @@
           int end_offset = end > 0 ? character_offsets[end - 1] : 0;
 
           switch (node->data().GetTextDirection()) {
-            case ax::mojom::TextDirection::kLtr:
+            case ax::mojom::WritingDirection::kLtr:
             default:
               local_bounds.set_x(local_bounds.x() + start_offset);
               local_bounds.set_width(end_offset - start_offset);
               break;
-            case ax::mojom::TextDirection::kRtl:
+            case ax::mojom::WritingDirection::kRtl:
               local_bounds.set_x(local_bounds.x() + local_bounds.width() -
                                  end_offset);
               local_bounds.set_width(end_offset - start_offset);
               break;
-            case ax::mojom::TextDirection::kTtb:
+            case ax::mojom::WritingDirection::kTtb:
               local_bounds.set_y(local_bounds.y() + start_offset);
               local_bounds.set_height(end_offset - start_offset);
               break;
-            case ax::mojom::TextDirection::kBtt:
+            case ax::mojom::WritingDirection::kBtt:
               local_bounds.set_y(local_bounds.y() + local_bounds.height() -
                                  end_offset);
               local_bounds.set_height(end_offset - start_offset);
diff --git a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
index e9005fbb..88f3393b 100644
--- a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
+++ b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
@@ -101,7 +101,7 @@
                                  new_client.InitWithNewPipeAndPassReceiver(),
                                  &original_loader, &original_client);
 
-    auto transferrable_loader = content::mojom::TransferrableURLLoader::New();
+    auto transferrable_loader = blink::mojom::TransferrableURLLoader::New();
     transferrable_loader->url_loader = std::move(original_loader);
     transferrable_loader->url_loader_client = std::move(original_client);
 
@@ -379,7 +379,7 @@
 }
 
 void MimeHandlerViewContainer::SetEmbeddedLoader(
-    content::mojom::TransferrableURLLoaderPtr transferrable_url_loader) {
+    blink::mojom::TransferrableURLLoaderPtr transferrable_url_loader) {
   transferrable_url_loader_ = std::move(transferrable_url_loader);
   transferrable_url_loader_->url = GURL(plugin_path_ + base::GenerateGUID());
   // Warning: It is possible that |this| gets destroyed after this line (when
diff --git a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
index 29bbe8fc..bf219605 100644
--- a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
+++ b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
@@ -14,7 +14,6 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "components/guest_view/renderer/guest_view_container.h"
-#include "content/public/common/transferrable_url_loader.mojom.h"
 #include "extensions/common/api/mime_handler.mojom.h"
 #include "extensions/common/guest_view/mime_handler_view_uma_types.h"
 #include "extensions/common/mojom/guest_view.mojom.h"
@@ -22,6 +21,7 @@
 #include "ipc/ipc_message.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
+#include "third_party/blink/public/mojom/loader/transferrable_url_loader.mojom.h"
 #include "third_party/blink/public/web/web_associated_url_loader_client.h"
 #include "ui/gfx/geometry/size.h"
 #include "url/gurl.h"
@@ -123,7 +123,7 @@
   // by the URLLoaderThrottle which intercepts the resource load, which is then
   // sent to the browser to be handed off to the plugin.
   void SetEmbeddedLoader(
-      content::mojom::TransferrableURLLoaderPtr transferrable_url_loader);
+      blink::mojom::TransferrableURLLoaderPtr transferrable_url_loader);
 
   void CreateMimeHandlerViewGuestIfNecessary();
   int32_t GetInstanceId() const;
@@ -157,7 +157,7 @@
   const std::string mime_type_;
 
   // Used when network service is enabled:
-  content::mojom::TransferrableURLLoaderPtr transferrable_url_loader_;
+  blink::mojom::TransferrableURLLoaderPtr transferrable_url_loader_;
 
   // Used when network service is disabled:
   // A URL loader to load the |original_url_| when the plugin is embedded. In
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index c6aa402..ba1dacdd 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -324,7 +324,10 @@
   ]
 
   if (use_ozone) {
-    deps += [ "//ui/ozone" ]
+    deps += [
+      "//ui/base:features",
+      "//ui/ozone",
+    ]
   }
 
   if (enable_vulkan) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index ccba700..693e293 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -118,6 +118,10 @@
 #include <OpenGL/CGLIOSurface.h>
 #endif  // OS_MACOSX
 
+#if defined(USE_OZONE)
+#include "ui/base/ui_base_features.h"  // nogncheck
+#endif
+
 // Note: this undefs far and near so include this after other Windows headers.
 #include "third_party/angle/src/image_util/loadimage.h"
 
@@ -3216,14 +3220,14 @@
   bool is_cleared = false;
   gfx::BufferFormat buffer_format = gfx::BufferFormat::RGBA_8888;
   if (format == GL_RGB) {
+    buffer_format = gfx::BufferFormat::RGBX_8888;
 #if defined(USE_OZONE)
     // BGRX format is preferred for Ozone as it matches the format used by the
     // buffer queue and is as a result guaranteed to work on all devices.
     // TODO(reveman): Define this format in one place instead of having to
     // duplicate BGRX_8888.
-    buffer_format = gfx::BufferFormat::BGRX_8888;
-#else
-    buffer_format = gfx::BufferFormat::RGBX_8888;
+    if (features::IsUsingOzonePlatform())
+      buffer_format = gfx::BufferFormat::BGRX_8888;
 #endif
   }
   scoped_refptr<gl::GLImage> image =
diff --git a/gpu/command_buffer/service/shared_context_state.cc b/gpu/command_buffer/service/shared_context_state.cc
index 479619f..f791025 100644
--- a/gpu/command_buffer/service/shared_context_state.cc
+++ b/gpu/command_buffer/service/shared_context_state.cc
@@ -104,7 +104,7 @@
     scoped_refptr<gl::GLSurface> surface,
     scoped_refptr<gl::GLContext> context,
     bool use_virtualized_gl_contexts,
-    base::OnceClosure context_lost_callback,
+    ContextLostCallback context_lost_callback,
     GrContextType gr_context_type,
     viz::VulkanContextProvider* vulkan_context_provider,
     viz::MetalContextProvider* metal_context_provider,
@@ -490,7 +490,8 @@
       gr_context_ = nullptr;
     }
     UpdateSkiaOwnedMemorySize();
-    std::move(context_lost_callback_).Run();
+    std::move(context_lost_callback_)
+        .Run(!context_lost_by_robustness_extension);
     for (auto& observer : context_lost_observers_)
       observer.OnContextLost();
   }
@@ -738,6 +739,7 @@
   LOG(ERROR) << "SharedContextState context lost via ARB/EXT_robustness. Reset "
                 "status = "
              << gles2::GLES2Util::GetStringEnum(driver_status);
+  context_lost_by_robustness_extension = true;
 
   switch (driver_status) {
     case GL_GUILTY_CONTEXT_RESET_ARB:
diff --git a/gpu/command_buffer/service/shared_context_state.h b/gpu/command_buffer/service/shared_context_state.h
index ec476f3..a835dc1 100644
--- a/gpu/command_buffer/service/shared_context_state.h
+++ b/gpu/command_buffer/service/shared_context_state.h
@@ -61,6 +61,8 @@
       public base::RefCounted<SharedContextState>,
       public GrContextOptions::ShaderErrorHandler {
  public:
+  using ContextLostCallback = base::OnceCallback<void(bool)>;
+
   // TODO: Refactor code to have seperate constructor for GL and Vulkan and not
   // initialize/use GL related info for vulkan and vice-versa.
   SharedContextState(
@@ -68,7 +70,7 @@
       scoped_refptr<gl::GLSurface> surface,
       scoped_refptr<gl::GLContext> context,
       bool use_virtualized_gl_contexts,
-      base::OnceClosure context_lost_callback,
+      ContextLostCallback context_lost_callback,
       GrContextType gr_context_type = GrContextType::kGL,
       viz::VulkanContextProvider* vulkan_context_provider = nullptr,
       viz::MetalContextProvider* metal_context_provider = nullptr,
@@ -250,7 +252,7 @@
 
   bool use_virtualized_gl_contexts_ = false;
   bool support_vulkan_external_object_ = false;
-  base::OnceClosure context_lost_callback_;
+  ContextLostCallback context_lost_callback_;
   GrContextType gr_context_type_ = GrContextType::kGL;
   MemoryTracker memory_tracker_;
   viz::VulkanContextProvider* const vk_context_provider_;
@@ -289,6 +291,7 @@
   base::MRUCache<void*, sk_sp<SkSurface>> sk_surface_cache_;
 
   bool device_needs_reset_ = false;
+  bool context_lost_by_robustness_extension = false;
   base::Time last_gl_check_graphics_reset_status_;
   bool disable_check_reset_status_throttling_for_test_ = false;
 
diff --git a/gpu/command_buffer/service/skia_utils.cc b/gpu/command_buffer/service/skia_utils.cc
index 6c6a8e28..cfa3d91 100644
--- a/gpu/command_buffer/service/skia_utils.cc
+++ b/gpu/command_buffer/service/skia_utils.cc
@@ -170,6 +170,7 @@
   DCHECK(!context_state->gr_context()->abandoned());
 
   if (!context_state->GrContextIsVulkan()) {
+    DCHECK(context_state->gr_context());
     context_state->gr_context()->deleteBackendTexture(
         std::move(*backend_texture));
     return;
diff --git a/gpu/command_buffer/service/wrapped_sk_image.cc b/gpu/command_buffer/service/wrapped_sk_image.cc
index 41b15653..76f4ead 100644
--- a/gpu/command_buffer/service/wrapped_sk_image.cc
+++ b/gpu/command_buffer/service/wrapped_sk_image.cc
@@ -446,6 +446,9 @@
     SharedImageManager* manager,
     MemoryTypeTracker* tracker,
     scoped_refptr<SharedContextState> context_state) {
+  if (context_state_->context_lost())
+    return nullptr;
+
   DCHECK_EQ(context_state_, context_state.get());
   return std::make_unique<WrappedSkImageRepresentation>(manager, this, tracker);
 }
diff --git a/gpu/ipc/common/gpu_memory_buffer_support.cc b/gpu/ipc/common/gpu_memory_buffer_support.cc
index 5d05df1..9bc45768 100644
--- a/gpu/ipc/common/gpu_memory_buffer_support.cc
+++ b/gpu/ipc/common/gpu_memory_buffer_support.cc
@@ -8,6 +8,7 @@
 #include "base/notreached.h"
 #include "build/build_config.h"
 #include "gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/buffer_usage_util.h"
 
@@ -46,8 +47,12 @@
 
 GpuMemoryBufferSupport::GpuMemoryBufferSupport() {
 #if defined(USE_OZONE)
-  client_native_pixmap_factory_ = ui::CreateClientNativePixmapFactoryOzone();
-#elif defined(OS_LINUX)
+  if (features::IsUsingOzonePlatform()) {
+    client_native_pixmap_factory_ = ui::CreateClientNativePixmapFactoryOzone();
+    return;
+  }
+#endif
+#if defined(OS_LINUX)
   client_native_pixmap_factory_.reset(
       gfx::CreateClientNativePixmapFactoryDmabuf());
 #endif
@@ -116,10 +121,13 @@
   }
   NOTREACHED();
   return false;
-#elif defined(USE_OZONE)
-  return ui::OzonePlatform::GetInstance()->IsNativePixmapConfigSupported(format,
-                                                                         usage);
-#elif defined(USE_X11)
+#elif defined(USE_OZONE) || defined(USE_X11)
+#if defined(USE_OZONE)
+  if (features::IsUsingOzonePlatform()) {
+    return ui::OzonePlatform::GetInstance()->IsNativePixmapConfigSupported(
+        format, usage);
+  }
+#endif
   // On X11, GPU memory buffer support can only be determined after GPU
   // initialization.
   // viz::HostGpuMemoryBufferManager::IsNativeGpuMemoryBufferConfiguration()
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc
index 98f44c24..231bea9 100644
--- a/gpu/ipc/service/gpu_channel_manager.cc
+++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -740,8 +740,7 @@
   auto shared_context_state = base::MakeRefCounted<SharedContextState>(
       std::move(share_group), std::move(surface), std::move(context),
       use_virtualized_gl_contexts,
-      base::BindOnce(&GpuChannelManager::OnContextLost, base::Unretained(this),
-                     /*synthetic_loss=*/false),
+      base::BindOnce(&GpuChannelManager::OnContextLost, base::Unretained(this)),
       gpu_preferences_.gr_context_type, vulkan_context_provider_,
       metal_context_provider_, dawn_context_provider_,
       peak_memory_monitor_.GetWeakPtr());
diff --git a/gpu/vulkan/BUILD.gn b/gpu/vulkan/BUILD.gn
index a6f86a9e..4af8209f 100644
--- a/gpu/vulkan/BUILD.gn
+++ b/gpu/vulkan/BUILD.gn
@@ -165,6 +165,7 @@
     sources = [ "tests/native_window.h" ]
 
     deps = [
+      "//ui/base:features",
       "//ui/gfx",
       "//ui/gfx:native_widget_types",
     ]
diff --git a/gpu/vulkan/tests/native_window.cc b/gpu/vulkan/tests/native_window.cc
index f8dce865..a2f7d15 100644
--- a/gpu/vulkan/tests/native_window.cc
+++ b/gpu/vulkan/tests/native_window.cc
@@ -5,6 +5,7 @@
 #include "gpu/vulkan/tests/native_window.h"
 
 #include "base/containers/flat_map.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/platform_window/platform_window_delegate.h"
 #include "ui/platform_window/platform_window_init_properties.h"
 
@@ -26,15 +27,23 @@
 
   void Initialize(const gfx::Rect& bounds) {
     DCHECK(!platform_window_);
+
+#if defined(USE_OZONE) || defined(USE_X11)
+    ui::PlatformWindowInitProperties props(bounds);
 #if defined(USE_OZONE)
-    ui::PlatformWindowInitProperties props(bounds);
-    platform_window_ = ui::OzonePlatform::GetInstance()->CreatePlatformWindow(
-        this, std::move(props));
-#elif defined(USE_X11)
-    ui::PlatformWindowInitProperties props(bounds);
-    auto x11_window = std::make_unique<ui::X11Window>(this);
-    x11_window->Initialize(std::move(props));
-    platform_window_ = std::move(x11_window);
+    if (features::IsUsingOzonePlatform()) {
+      platform_window_ = ui::OzonePlatform::GetInstance()->CreatePlatformWindow(
+          this, std::move(props));
+    }
+#endif
+#if defined(USE_X11)
+    if (!platform_window_) {
+      DCHECK(!features::IsUsingOzonePlatform());
+      auto x11_window = std::make_unique<ui::X11Window>(this);
+      x11_window->Initialize(std::move(props));
+      platform_window_ = std::move(x11_window);
+    }
+#endif
 #else
     NOTIMPLEMENTED();
     return;
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index e022b85..eac25f7 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -140,7 +140,6 @@
     ":app",
     ":blocking_scene_commands",
     ":mode",
-    ":scoped_ui_blocker",
     ":tests_hook",
     "//base",
     "//build:branding_buildflags",
@@ -223,6 +222,7 @@
     "//ios/chrome/browser/ui/main",
     "//ios/chrome/browser/ui/main:scene",
     "//ios/chrome/browser/ui/main:scene_guts",
+    "//ios/chrome/browser/ui/scoped_ui_blocker",
     "//ios/chrome/browser/ui/tab_grid",
     "//ios/chrome/browser/ui/tab_grid:tab_grid_ui",
     "//ios/chrome/browser/ui/table_view",
@@ -278,25 +278,6 @@
   deps = [ "//base" ]
 }
 
-source_set("scoped_ui_blocker") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  sources = [
-    "scoped_ui_blocker.h",
-    "scoped_ui_blocker.mm",
-  ]
-
-  deps = [
-    "//base",
-    "//ios/chrome/app/application_delegate:application_delegate_internal",
-    "//ios/chrome/browser/ui/main:scene",
-  ]
-
-  allow_circular_includes_from = [
-    "//ios/chrome/app/application_delegate:application_delegate_internal",
-    "//ios/chrome/browser/ui/main:scene",
-  ]
-}
-
 source_set("mode") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [ "application_mode.h" ]
diff --git a/ios/chrome/app/application_delegate/BUILD.gn b/ios/chrome/app/application_delegate/BUILD.gn
index e5a53448..07b6c38 100644
--- a/ios/chrome/app/application_delegate/BUILD.gn
+++ b/ios/chrome/app/application_delegate/BUILD.gn
@@ -211,6 +211,8 @@
     "//ui/base",
     "//url",
   ]
+  public_deps = [ "//ios/chrome/browser/ui/scoped_ui_blocker" ]
+
   if (ios_enable_metrickit) {
     deps += [ ":metric_kit_subscriber" ]
   }
diff --git a/ios/chrome/app/application_delegate/app_state.h b/ios/chrome/app/application_delegate/app_state.h
index a3a20c5..02e498c 100644
--- a/ios/chrome/app/application_delegate/app_state.h
+++ b/ios/chrome/app/application_delegate/app_state.h
@@ -7,6 +7,8 @@
 
 #import <UIKit/UIKit.h>
 
+#import "ios/chrome/browser/ui/scoped_ui_blocker/ui_blocker_manager.h"
+
 @class AppState;
 @protocol BrowserLauncher;
 @class CommandDispatcher;
@@ -34,7 +36,7 @@
 
 // Represents the application state and responds to application state changes
 // and system events.
-@interface AppState : NSObject
+@interface AppState : NSObject <UIBlockerManager>
 
 - (instancetype)init NS_UNAVAILABLE;
 
@@ -61,13 +63,6 @@
 // is shown. When there is no blocking UI shown in any scene, this is nil.
 @property(nonatomic, weak, readonly) SceneState* sceneShowingBlockingUI;
 
-// Call this when showing a new blocking UI in |scene|.
-// It is an error to call this for scene A when scene B is already showing one
-// or more blocking UI.
-- (void)incrementBlockingUICounterForScene:(SceneState*)scene;
-// Call this after dismissing a blocking UI.
-- (void)decrementBlockingUICounter;
-
 // Saves the launchOptions to be used from -newTabFromLaunchOptions. If the
 // application is in background, initialize the browser to basic. If not, launch
 // the browser.
diff --git a/ios/chrome/app/application_delegate/app_state.mm b/ios/chrome/app/application_delegate/app_state.mm
index bdc925b..dfb1c13 100644
--- a/ios/chrome/app/application_delegate/app_state.mm
+++ b/ios/chrome/app/application_delegate/app_state.mm
@@ -26,7 +26,6 @@
 #import "ios/chrome/app/application_delegate/user_activity_handler.h"
 #import "ios/chrome/app/deferred_initialization_runner.h"
 #import "ios/chrome/app/main_application_delegate.h"
-#import "ios/chrome/app/scoped_ui_blocker.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_constants.h"
@@ -53,6 +52,7 @@
 #import "ios/chrome/browser/ui/main/scene_delegate.h"
 #import "ios/chrome/browser/ui/main/scene_state.h"
 #import "ios/chrome/browser/ui/safe_mode/safe_mode_coordinator.h"
+#import "ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.h"
 #import "ios/chrome/browser/ui/util/multi_window_support.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_metrics_browser_agent.h"
@@ -143,8 +143,8 @@
 // never reset.
 @property(nonatomic, assign) BOOL firstSceneHasActivated;
 
-// Redefined as readwrite.
-@property(nonatomic, weak, readwrite) SceneState* sceneShowingBlockingUI;
+// The current blocker target if any.
+@property(nonatomic, weak, readwrite) id<UIBlockerTarget> uiBlockerTarget;
 
 // The counter of currently shown blocking UIs. Do not use this directly,
 // instead use incrementBlockingUICounterForScene: and
@@ -196,14 +196,15 @@
   _safeModeCoordinator = safeModeCoordinator;
 }
 
-- (void)setSceneShowingBlockingUI:(SceneState*)newScene {
-  _sceneShowingBlockingUI = newScene;
-    for (SceneState* scene in self.connectedScenes) {
-      // When there's a scene with blocking UI, all other scenes should show the
-      // overlay.
-      BOOL shouldPresentOverlay = (newScene != nil) && (scene != newScene);
-      scene.presentingModalOverlay = shouldPresentOverlay;
-    }
+- (void)setUiBlockerTarget:(id<UIBlockerTarget>)uiBlockerTarget {
+  _uiBlockerTarget = uiBlockerTarget;
+  for (SceneState* scene in self.connectedScenes) {
+    // When there's a scene with blocking UI, all other scenes should show the
+    // overlay.
+    BOOL shouldPresentOverlay =
+        (uiBlockerTarget != nil) && (scene != uiBlockerTarget);
+    scene.presentingModalOverlay = shouldPresentOverlay;
+  }
 }
 
 #pragma mark - Public methods.
@@ -531,24 +532,6 @@
 
 #pragma mark - Multiwindow-related
 
-- (void)decrementBlockingUICounter {
-  DCHECK(self.blockingUICounter > 0 && self.sceneShowingBlockingUI != nil);
-  self.blockingUICounter--;
-  if (self.blockingUICounter == 0) {
-    self.sceneShowingBlockingUI = nil;
-  }
-}
-
-- (void)incrementBlockingUICounterForScene:(SceneState*)scene {
-  DCHECK(self.sceneShowingBlockingUI == nil ||
-         scene == self.sceneShowingBlockingUI)
-      << "Another scene is already showing a blocking UI!";
-  self.blockingUICounter++;
-  if (!self.sceneShowingBlockingUI) {
-    self.sceneShowingBlockingUI = scene;
-  }
-}
-
 - (SceneState*)foregroundActiveScene {
   for (SceneState* sceneState in self.connectedScenes) {
     if (sceneState.activationLevel == SceneActivationLevelForegroundActive) {
@@ -616,8 +599,10 @@
 
   [self.safeModeCoordinator start];
 
-  _safeModeBlocker =
-      std::make_unique<ScopedUIBlocker>(self.foregroundActiveScene);
+  if (IsMultiwindowSupported()) {
+    _safeModeBlocker =
+        std::make_unique<ScopedUIBlocker>(self.foregroundActiveScene);
+  }
 }
 
 - (void)initializeUI {
@@ -656,6 +641,25 @@
   [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
 }
 
+#pragma mark - UIBlockerManager
+
+- (void)incrementBlockingUICounterForTarget:(id<UIBlockerTarget>)target {
+  DCHECK(self.uiBlockerTarget == nil || target == self.uiBlockerTarget)
+      << "Another scene is already showing a blocking UI!";
+  self.blockingUICounter++;
+  if (!self.uiBlockerTarget) {
+    self.uiBlockerTarget = target;
+  }
+}
+
+- (void)decrementBlockingUICounterForTarget:(id<UIBlockerTarget>)target {
+  DCHECK(self.blockingUICounter > 0 && self.uiBlockerTarget == target);
+  self.blockingUICounter--;
+  if (self.blockingUICounter == 0) {
+    self.uiBlockerTarget = nil;
+  }
+}
+
 #pragma mark - Scene notifications
 
 // Handler for UISceneDidActivateNotification.
@@ -680,8 +684,8 @@
       }
     }
     sceneDelegate.sceneState.presentingModalOverlay =
-        self.sceneShowingBlockingUI &&
-        (self.sceneShowingBlockingUI != sceneDelegate.sceneState);
+        (self.uiBlockerTarget != nil) &&
+        (self.uiBlockerTarget != sceneDelegate.sceneState);
   }
 }
 
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index d49aa0c..4baebba 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -28,7 +28,6 @@
 #import "ios/chrome/app/blocking_scene_commands.h"
 #import "ios/chrome/app/deferred_initialization_runner.h"
 #import "ios/chrome/app/memory_monitor.h"
-#import "ios/chrome/app/scoped_ui_blocker.h"
 #import "ios/chrome/app/spotlight/spotlight_manager.h"
 #include "ios/chrome/app/startup/chrome_main_starter.h"
 #include "ios/chrome/app/startup/client_registration.h"
@@ -90,6 +89,7 @@
 #import "ios/chrome/browser/ui/main/browser_view_wrangler.h"
 #import "ios/chrome/browser/ui/main/scene_controller_guts.h"
 #import "ios/chrome/browser/ui/main/scene_delegate.h"
+#import "ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.h"
 #import "ios/chrome/browser/ui/ui_feature_flags.h"
 #include "ios/chrome/browser/ui/util/multi_window_support.h"
 #import "ios/chrome/browser/ui/webui/chrome_web_ui_ios_controller_factory.h"
@@ -262,9 +262,6 @@
 
   // Hander for the startup tasks, deferred or not.
   StartupTasks* _startupTasks;
-
-  // UI blocker used during first run in multiwindow.
-  std::unique_ptr<ScopedUIBlocker> _firstRunUIBlocker;
 }
 
 // The ChromeBrowserState associated with the main (non-OTR) browsing mode.
@@ -607,10 +604,6 @@
               object:nil];
 
   [self markEulaAsAccepted];
-
-  if (IsMultiwindowSupported()) {
-    _firstRunUIBlocker.reset();
-  }
 }
 
 - (void)handleFirstRunUIDidFinish {
@@ -1085,11 +1078,6 @@
          selector:@selector(handleFirstRunUIDidFinish)
              name:kChromeFirstRunUIDidFinishNotification
            object:nil];
-
-  if (IsMultiwindowSupported()) {
-    // Update the AppState.
-    _firstRunUIBlocker = std::make_unique<ScopedUIBlocker>(presentingScene);
-  }
 }
 
 - (void)crashIfRequested {
diff --git a/ios/chrome/app/scoped_ui_blocker.h b/ios/chrome/app/scoped_ui_blocker.h
deleted file mode 100644
index 86bbec3c..0000000
--- a/ios/chrome/app/scoped_ui_blocker.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_APP_SCOPED_UI_BLOCKER_H_
-#define IOS_CHROME_APP_SCOPED_UI_BLOCKER_H_
-
-#include "base/logging.h"
-#include "base/macros.h"
-#import "ios/chrome/app/application_delegate/app_state.h"
-#import "ios/chrome/browser/ui/main/scene_state.h"
-
-// A helper object that increments AppState's blocking UI counter for
-// its entire lifetime.
-class ScopedUIBlocker {
- public:
-  explicit ScopedUIBlocker(SceneState* scene);
-  ~ScopedUIBlocker();
-
- private:
-  // The scene showing the blocking UI.
-  __weak SceneState* scene_;
-
-  ScopedUIBlocker(const ScopedUIBlocker&) = delete;
-  ScopedUIBlocker& operator=(const ScopedUIBlocker&) = delete;
-};
-
-#endif  // IOS_CHROME_APP_SCOPED_UI_BLOCKER_H_
diff --git a/ios/chrome/app/scoped_ui_blocker.mm b/ios/chrome/app/scoped_ui_blocker.mm
deleted file mode 100644
index 9bcf36a8..0000000
--- a/ios/chrome/app/scoped_ui_blocker.mm
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/app/scoped_ui_blocker.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-ScopedUIBlocker::ScopedUIBlocker(SceneState* scene) : scene_(scene) {
-  DCHECK(scene_);
-  AppState* appState = scene.appState;
-  DCHECK(appState.sceneShowingBlockingUI == nil ||
-         appState.sceneShowingBlockingUI == scene_)
-      << "Another scene is already showing a blocking UI!";
-  [appState incrementBlockingUICounterForScene:scene];
-}
-
-ScopedUIBlocker::~ScopedUIBlocker() {
-  [scene_.appState decrementBlockingUICounter];
-}
diff --git a/ios/chrome/browser/ui/commands/command_dispatcher.mm b/ios/chrome/browser/ui/commands/command_dispatcher.mm
index 08d7d62..5e569fca 100644
--- a/ios/chrome/browser/ui/commands/command_dispatcher.mm
+++ b/ios/chrome/browser/ui/commands/command_dispatcher.mm
@@ -110,7 +110,7 @@
 
 - (CommandDispatcher*)strictCallableForProtocol:(Protocol*)protocol {
   CHECK([self dispatchingForProtocol:protocol])
-      << "Dispatcher failed protocol confromance";
+      << "Dispatcher failed protocol conformance";
   return self;
 }
 
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
index f50db87..dd1a1db 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
@@ -56,10 +56,11 @@
 
 }  // namespace
 
-@interface ContentSuggestionsMediator ()<ContentSuggestionsItemDelegate,
-                                         ContentSuggestionsServiceObserver,
-                                         MostVisitedSitesObserving,
-                                         ReadingListModelBridgeObserver> {
+@interface ContentSuggestionsMediator () <BooleanObserver,
+                                          ContentSuggestionsItemDelegate,
+                                          ContentSuggestionsServiceObserver,
+                                          MostVisitedSitesObserving,
+                                          ReadingListModelBridgeObserver> {
   // Bridge for this class to become an observer of a ContentSuggestionsService.
   std::unique_ptr<ContentSuggestionsServiceBridge> _suggestionBridge;
   std::unique_ptr<ntp_tiles::MostVisitedSites> _mostVisitedSites;
@@ -369,22 +370,13 @@
 
 - (void)toggleArticlesVisibility {
   [self.contentArticlesExpanded setValue:![self.contentArticlesExpanded value]];
+  [self reloadArticleSection];
+}
 
-  // Update the section information for new collapsed state.
-  ntp_snippets::Category category = ntp_snippets::Category::FromKnownCategory(
-      ntp_snippets::KnownCategories::ARTICLES);
-  ContentSuggestionsCategoryWrapper* wrapper =
-      [ContentSuggestionsCategoryWrapper wrapperWithCategory:category];
-  ContentSuggestionsSectionInformation* sectionInfo =
-      self.sectionInformationByCategory[wrapper];
-  sectionInfo.expanded = [self.contentArticlesExpanded value];
+#pragma mark - BooleanObserver
 
-  // Reloading the section with animations looks bad because the section
-  // border with the new collapsed height draws before the elements collapse.
-  BOOL animationsWereEnabled = [UIView areAnimationsEnabled];
-  [UIView setAnimationsEnabled:NO];
-  [self.dataSink reloadSection:sectionInfo];
-  [UIView setAnimationsEnabled:animationsWereEnabled];
+- (void)booleanDidChange:(id<ObservableBoolean>)observableBoolean {
+  [self reloadArticleSection];
 }
 
 #pragma mark - ContentSuggestionsServiceObserver
@@ -563,6 +555,24 @@
 
 #pragma mark - Private
 
+- (void)reloadArticleSection {
+  // Update the section information for new collapsed state.
+  ntp_snippets::Category category = ntp_snippets::Category::FromKnownCategory(
+      ntp_snippets::KnownCategories::ARTICLES);
+  ContentSuggestionsCategoryWrapper* wrapper =
+      [ContentSuggestionsCategoryWrapper wrapperWithCategory:category];
+  ContentSuggestionsSectionInformation* sectionInfo =
+      self.sectionInformationByCategory[wrapper];
+  sectionInfo.expanded = [self.contentArticlesExpanded value];
+
+  // Reloading the section with animations looks bad because the section
+  // border with the new collapsed height draws before the elements collapse.
+  BOOL animationsWereEnabled = [UIView areAnimationsEnabled];
+  [UIView setAnimationsEnabled:NO];
+  [self.dataSink reloadSection:sectionInfo];
+  [UIView setAnimationsEnabled:animationsWereEnabled];
+}
+
 // Converts the |suggestions| from |category| to CSCollectionViewItem and adds
 // them to the |contentArray| if the category is available.
 - (void)addSuggestions:
@@ -705,6 +715,13 @@
   }
 }
 
+- (void)setContentArticlesExpanded:(PrefBackedBoolean*)contentArticlesExpanded {
+  if (_contentArticlesExpanded == contentArticlesExpanded)
+    return;
+  _contentArticlesExpanded = contentArticlesExpanded;
+  [contentArticlesExpanded setObserver:self];
+}
+
 #pragma mark - ReadingListModelBridgeObserver
 
 - (void)readingListModelLoaded:(const ReadingListModel*)model {
diff --git a/ios/chrome/browser/ui/favicon/BUILD.gn b/ios/chrome/browser/ui/favicon/BUILD.gn
index 46d07c2..adb21cf 100644
--- a/ios/chrome/browser/ui/favicon/BUILD.gn
+++ b/ios/chrome/browser/ui/favicon/BUILD.gn
@@ -11,7 +11,6 @@
   ]
   deps = [
     "resources:default_favicon",
-    "resources:default_world_favicon",
     "resources:default_world_favicon_incognito",
     "resources:default_world_favicon_regular",
     "//base",
@@ -20,6 +19,7 @@
     "//ios/chrome/browser/favicon",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/common/ui/favicon",
+    "//ios/chrome/common/ui/resources:default_world_favicon",
     "//url",
   ]
   configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/chrome/browser/ui/favicon/resources/BUILD.gn b/ios/chrome/browser/ui/favicon/resources/BUILD.gn
index 3d7c12a..481b51e 100644
--- a/ios/chrome/browser/ui/favicon/resources/BUILD.gn
+++ b/ios/chrome/browser/ui/favicon/resources/BUILD.gn
@@ -4,15 +4,6 @@
 
 import("//build/config/ios/asset_catalog.gni")
 
-imageset("default_world_favicon") {
-  sources = [
-    "default_world_favicon.imageset/Contents.json",
-    "default_world_favicon.imageset/default_world_favicon.png",
-    "default_world_favicon.imageset/default_world_favicon@2x.png",
-    "default_world_favicon.imageset/default_world_favicon@3x.png",
-  ]
-}
-
 imageset("default_world_favicon_incognito") {
   sources = [
     "default_world_favicon_incognito.imageset/Contents.json",
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn
index e77d3b0f..414211a 100644
--- a/ios/chrome/browser/ui/main/BUILD.gn
+++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -85,6 +85,7 @@
     "//ios/public/provider/chrome/browser/signin",
     "//ios/public/provider/chrome/browser/user_feedback",
   ]
+  public_deps = [ "//ios/chrome/browser/ui/scoped_ui_blocker" ]
 
   allow_circular_includes_from = [ ":main" ]
 
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm
index a5d5c0f5..563991f 100644
--- a/ios/chrome/browser/ui/main/scene_controller.mm
+++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -22,7 +22,6 @@
 #import "ios/chrome/app/chrome_overlay_window.h"
 #import "ios/chrome/app/deferred_initialization_runner.h"
 #import "ios/chrome/app/main_controller_guts.h"
-#import "ios/chrome/app/scoped_ui_blocker.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_remove_mask.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_remover.h"
@@ -62,6 +61,7 @@
 #include "ios/chrome/browser/ui/history/history_coordinator.h"
 #import "ios/chrome/browser/ui/main/browser_interface_provider.h"
 #import "ios/chrome/browser/ui/main/browser_view_wrangler.h"
+#import "ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.h"
 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
 #include "ios/chrome/browser/ui/tab_grid/tab_grid_coordinator.h"
 #import "ios/chrome/browser/ui/ui_feature_flags.h"
diff --git a/ios/chrome/browser/ui/main/scene_state.h b/ios/chrome/browser/ui/main/scene_state.h
index 5b1d4dc..e627b94 100644
--- a/ios/chrome/browser/ui/main/scene_state.h
+++ b/ios/chrome/browser/ui/main/scene_state.h
@@ -7,6 +7,7 @@
 
 #import <UIKit/UIKit.h>
 
+#import "ios/chrome/browser/ui/scoped_ui_blocker/ui_blocker_target.h"
 #import "ios/chrome/browser/window_activities/window_activity_helpers.h"
 
 @class AppState;
@@ -55,7 +56,7 @@
 
 // An object containing the state of a UIWindowScene. One state object
 // corresponds to one scene.
-@interface SceneState : NSObject
+@interface SceneState : NSObject <UIBlockerTarget>
 
 - (instancetype)initWithAppState:(AppState*)appState NS_DESIGNATED_INITIALIZER;
 - (instancetype)init NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/main/scene_state.mm b/ios/chrome/browser/ui/main/scene_state.mm
index e63656b8..0c7c61a9 100644
--- a/ios/chrome/browser/ui/main/scene_state.mm
+++ b/ios/chrome/browser/ui/main/scene_state.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/main/scene_state.h"
 
 #import "base/ios/crb_protocol_observers.h"
+#import "ios/chrome/app/application_delegate/app_state.h"
 #import "ios/chrome/app/chrome_overlay_window.h"
 #import "ios/chrome/browser/ui/main/scene_controller.h"
 #import "ios/chrome/browser/ui/util/multi_window_support.h"
@@ -117,6 +118,10 @@
   [self.observers sceneState:self receivedUserActivity:pendingUserActivity];
 }
 
+- (id<UIBlockerManager>)uiBlockerManager {
+  return _appState;
+}
+
 #pragma mark - debug
 
 - (NSString*)description {
diff --git a/ios/chrome/browser/ui/scoped_ui_blocker/BUILD.gn b/ios/chrome/browser/ui/scoped_ui_blocker/BUILD.gn
new file mode 100644
index 0000000..88a63b6d
--- /dev/null
+++ b/ios/chrome/browser/ui/scoped_ui_blocker/BUILD.gn
@@ -0,0 +1,16 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("scoped_ui_blocker") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "scoped_ui_blocker.h",
+    "scoped_ui_blocker.h",
+    "scoped_ui_blocker.mm",
+    "ui_blocker_manager.h",
+    "ui_blocker_target.h",
+  ]
+
+  deps = [ "//base" ]
+}
diff --git a/ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.h b/ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.h
new file mode 100644
index 0000000..e0c97b39
--- /dev/null
+++ b/ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.h
@@ -0,0 +1,31 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_SCOPED_UI_BLOCKER_SCOPED_UI_BLOCKER_H_
+#define IOS_CHROME_BROWSER_UI_SCOPED_UI_BLOCKER_SCOPED_UI_BLOCKER_H_
+
+#import <Foundation/Foundation.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+
+@protocol UIBlockerManager;
+@protocol UIBlockerTarget;
+
+// A helper object that increments AppState's blocking UI counter for
+// its entire lifetime.
+class ScopedUIBlocker {
+ public:
+  explicit ScopedUIBlocker(id<UIBlockerTarget> target);
+  ~ScopedUIBlocker();
+
+ private:
+  // The target showing the blocking UI.
+  __weak id<UIBlockerTarget> target_;
+
+  ScopedUIBlocker(const ScopedUIBlocker&) = delete;
+  ScopedUIBlocker& operator=(const ScopedUIBlocker&) = delete;
+};
+
+#endif  // IOS_CHROME_BROWSER_UI_SCOPED_UI_BLOCKER_SCOPED_UI_BLOCKER_H_
diff --git a/ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.mm b/ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.mm
new file mode 100644
index 0000000..d069e6f0
--- /dev/null
+++ b/ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.mm
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.h"
+
+#import "base/check.h"
+#import "ios/chrome/browser/ui/scoped_ui_blocker/ui_blocker_manager.h"
+#import "ios/chrome/browser/ui/scoped_ui_blocker/ui_blocker_target.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+ScopedUIBlocker::ScopedUIBlocker(id<UIBlockerTarget> target) : target_(target) {
+  DCHECK(target_);
+  id<UIBlockerManager> uiBlockerManager = target.uiBlockerManager;
+  DCHECK(uiBlockerManager);
+  [uiBlockerManager incrementBlockingUICounterForTarget:target_];
+}
+
+ScopedUIBlocker::~ScopedUIBlocker() {
+  DCHECK(target_) << "Cannot unlock the blocking UI if scene is deallocated.";
+  [target_.uiBlockerManager decrementBlockingUICounterForTarget:target_];
+}
diff --git a/ios/chrome/browser/ui/scoped_ui_blocker/ui_blocker_manager.h b/ios/chrome/browser/ui/scoped_ui_blocker/ui_blocker_manager.h
new file mode 100644
index 0000000..ba18fcf
--- /dev/null
+++ b/ios/chrome/browser/ui/scoped_ui_blocker/ui_blocker_manager.h
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_SCOPED_UI_BLOCKER_UI_BLOCKER_MANAGER_H_
+#define IOS_CHROME_BROWSER_UI_SCOPED_UI_BLOCKER_UI_BLOCKER_MANAGER_H_
+
+#import <Foundation/Foundation.h>
+
+@protocol UIBlockerTarget;
+
+// Manager in charge to block and unblock all UI.
+@protocol UIBlockerManager <NSObject>
+
+// Call this when showing a new blocking UI in |target|.
+// It is an error to call this for target A when target B is already showing one
+// or more blocking UI.
+// This method can be called multiple time with the same target, before calling
+// |decrementBlockingUICounterForTarget:|.
+- (void)incrementBlockingUICounterForTarget:(id<UIBlockerTarget>)target;
+// Call this after dismissing a blocking UI.
+// |target| has to be the same value when |incrementBlockingUICounterForTarget:|
+// was called.
+- (void)decrementBlockingUICounterForTarget:(id<UIBlockerTarget>)target;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SCOPED_UI_BLOCKER_UI_BLOCKER_MANAGER_H_
diff --git a/ios/chrome/browser/ui/scoped_ui_blocker/ui_blocker_target.h b/ios/chrome/browser/ui/scoped_ui_blocker/ui_blocker_target.h
new file mode 100644
index 0000000..cde00282
--- /dev/null
+++ b/ios/chrome/browser/ui/scoped_ui_blocker/ui_blocker_target.h
@@ -0,0 +1,20 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_SCOPED_UI_BLOCKER_UI_BLOCKER_TARGET_H_
+#define IOS_CHROME_BROWSER_UI_SCOPED_UI_BLOCKER_UI_BLOCKER_TARGET_H_
+
+#import <Foundation/Foundation.h>
+
+@protocol UIBlockerManager;
+
+// Target to block all UI.
+@protocol UIBlockerTarget <NSObject>
+
+// Returns UI blocker manager.
+@property(nonatomic, weak, readonly) id<UIBlockerManager> uiBlockerManager;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SCOPED_UI_BLOCKER_UI_BLOCKER_TARGET_H_
diff --git a/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm
index 81d0347..8b6a855 100644
--- a/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm
@@ -143,6 +143,7 @@
 
 - (void)viewWillDisappear:(BOOL)animated {
   [super viewWillDisappear:animated];
+  [self.navigationController setToolbarHidden:YES animated:YES];
 }
 
 - (void)setEditing:(BOOL)editing animated:(BOOL)animated {
diff --git a/ios/chrome/browser/ui/tabs/BUILD.gn b/ios/chrome/browser/ui/tabs/BUILD.gn
index f3b4f35..80be000 100644
--- a/ios/chrome/browser/ui/tabs/BUILD.gn
+++ b/ios/chrome/browser/ui/tabs/BUILD.gn
@@ -48,7 +48,6 @@
     "//ios/chrome/browser/ui/colors",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/elements",
-    "//ios/chrome/browser/ui/favicon/resources:default_world_favicon",
     "//ios/chrome/browser/ui/fullscreen",
     "//ios/chrome/browser/ui/fullscreen:feature_flags",
     "//ios/chrome/browser/ui/image_util",
@@ -64,6 +63,7 @@
     "//ios/chrome/common",
     "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/elements",
+    "//ios/chrome/common/ui/resources:default_world_favicon",
     "//ios/chrome/common/ui/util",
     "//ios/third_party/material_components_ios",
     "//ios/web",
diff --git a/ios/chrome/browser/web/tab_order_egtest.mm b/ios/chrome/browser/web/tab_order_egtest.mm
index 9b180c0..ebbb0184 100644
--- a/ios/chrome/browser/web/tab_order_egtest.mm
+++ b/ios/chrome/browser/web/tab_order_egtest.mm
@@ -47,7 +47,8 @@
 @implementation TabOrderTestCase
 
 // Tests that new tabs are always inserted after their parent tab.
-- (void)testChildTabOrdering {
+// TODO(crbug.com/1106739): reenable this test.
+- (void)DISABLED_testChildTabOrdering {
   GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
   const GURL URL1 = self.testServer->GetURL(kLinksTestURL1);
 
@@ -61,8 +62,6 @@
                         [ElementSelector selectorWithElementID:kLinkSelectorID],
                         true /* menu should appear */)];
   [[EarlGrey selectElementWithMatcher:OpenLinkInNewTabButton()]
-      assertWithMatcher:grey_notNil()];
-  [[EarlGrey selectElementWithMatcher:OpenLinkInNewTabButton()]
       performAction:grey_tap()];
   [ChromeEarlGrey waitForMainTabCount:2U];
   NSString* childTab1ID = [ChromeEarlGrey nextTabID];
diff --git a/ios/chrome/common/ui/resources/BUILD.gn b/ios/chrome/common/ui/resources/BUILD.gn
new file mode 100644
index 0000000..ff6b3a9e
--- /dev/null
+++ b/ios/chrome/common/ui/resources/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ios/asset_catalog.gni")
+
+imageset("default_world_favicon") {
+  sources = [
+    "default_world_favicon.imageset/Contents.json",
+    "default_world_favicon.imageset/default_world_favicon.png",
+    "default_world_favicon.imageset/default_world_favicon@2x.png",
+    "default_world_favicon.imageset/default_world_favicon@3x.png",
+  ]
+}
diff --git a/ios/chrome/browser/ui/favicon/resources/default_world_favicon.imageset/Contents.json b/ios/chrome/common/ui/resources/default_world_favicon.imageset/Contents.json
similarity index 100%
rename from ios/chrome/browser/ui/favicon/resources/default_world_favicon.imageset/Contents.json
rename to ios/chrome/common/ui/resources/default_world_favicon.imageset/Contents.json
diff --git a/ios/chrome/browser/ui/favicon/resources/default_world_favicon.imageset/default_world_favicon.png b/ios/chrome/common/ui/resources/default_world_favicon.imageset/default_world_favicon.png
similarity index 100%
rename from ios/chrome/browser/ui/favicon/resources/default_world_favicon.imageset/default_world_favicon.png
rename to ios/chrome/common/ui/resources/default_world_favicon.imageset/default_world_favicon.png
Binary files differ
diff --git a/ios/chrome/browser/ui/favicon/resources/default_world_favicon.imageset/default_world_favicon@2x.png b/ios/chrome/common/ui/resources/default_world_favicon.imageset/default_world_favicon@2x.png
similarity index 100%
rename from ios/chrome/browser/ui/favicon/resources/default_world_favicon.imageset/default_world_favicon@2x.png
rename to ios/chrome/common/ui/resources/default_world_favicon.imageset/default_world_favicon@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/favicon/resources/default_world_favicon.imageset/default_world_favicon@3x.png b/ios/chrome/common/ui/resources/default_world_favicon.imageset/default_world_favicon@3x.png
similarity index 100%
rename from ios/chrome/browser/ui/favicon/resources/default_world_favicon.imageset/default_world_favicon@3x.png
rename to ios/chrome/common/ui/resources/default_world_favicon.imageset/default_world_favicon@3x.png
Binary files differ
diff --git a/ios/chrome/credential_provider_extension/ui/BUILD.gn b/ios/chrome/credential_provider_extension/ui/BUILD.gn
index fed9800..19e3010 100644
--- a/ios/chrome/credential_provider_extension/ui/BUILD.gn
+++ b/ios/chrome/credential_provider_extension/ui/BUILD.gn
@@ -34,6 +34,7 @@
     "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/confirmation_alert",
     "//ios/chrome/common/ui/elements:popover_label_view_controller",
+    "//ios/chrome/common/ui/resources:default_world_favicon",
     "//ios/chrome/common/ui/util",
     "//ios/chrome/credential_provider_extension:metrics_util",
     "//ios/chrome/credential_provider_extension:password_util",
diff --git a/ios/chrome/credential_provider_extension/ui/resources/BUILD.gn b/ios/chrome/credential_provider_extension/ui/resources/BUILD.gn
index cc216de..fcd7da9 100644
--- a/ios/chrome/credential_provider_extension/ui/resources/BUILD.gn
+++ b/ios/chrome/credential_provider_extension/ui/resources/BUILD.gn
@@ -8,7 +8,6 @@
 group("resources") {
   deps = [
     ":consent_illustration",
-    ":default_world_favicon",
     ":empty_credentials_illustration",
     ":info_icon",
     ":password_hide_icon",
@@ -52,15 +51,6 @@
   ]
 }
 
-imageset("default_world_favicon") {
-  sources = [
-    "default_world_favicon.imageset/Contents.json",
-    "default_world_favicon.imageset/default_world_favicon.png",
-    "default_world_favicon.imageset/default_world_favicon@2x.png",
-    "default_world_favicon.imageset/default_world_favicon@3x.png",
-  ]
-}
-
 imageset("info_icon") {
   sources = [
     "info_icon.imageset/Contents.json",
diff --git a/ios/chrome/credential_provider_extension/ui/resources/default_world_favicon.imageset/Contents.json b/ios/chrome/credential_provider_extension/ui/resources/default_world_favicon.imageset/Contents.json
deleted file mode 100644
index 3614ccd..0000000
--- a/ios/chrome/credential_provider_extension/ui/resources/default_world_favicon.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "default_world_favicon.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "default_world_favicon@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "default_world_favicon@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/credential_provider_extension/ui/resources/default_world_favicon.imageset/default_world_favicon.png b/ios/chrome/credential_provider_extension/ui/resources/default_world_favicon.imageset/default_world_favicon.png
deleted file mode 100644
index 3b6c9360..0000000
--- a/ios/chrome/credential_provider_extension/ui/resources/default_world_favicon.imageset/default_world_favicon.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/credential_provider_extension/ui/resources/default_world_favicon.imageset/default_world_favicon@2x.png b/ios/chrome/credential_provider_extension/ui/resources/default_world_favicon.imageset/default_world_favicon@2x.png
deleted file mode 100644
index 72b0b7c..0000000
--- a/ios/chrome/credential_provider_extension/ui/resources/default_world_favicon.imageset/default_world_favicon@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/credential_provider_extension/ui/resources/default_world_favicon.imageset/default_world_favicon@3x.png b/ios/chrome/credential_provider_extension/ui/resources/default_world_favicon.imageset/default_world_favicon@3x.png
deleted file mode 100644
index 7d10a12..0000000
--- a/ios/chrome/credential_provider_extension/ui/resources/default_world_favicon.imageset/default_world_favicon@3x.png
+++ /dev/null
Binary files differ
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
index 7c41163..730e5fe 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
@@ -120,7 +120,7 @@
     {{interface_macros.declare_sync_method_params("param_", method)}}) {
 #if BUILDFLAG(MOJO_TRACE_ENABLED)
 {%-     set qualified_method_name = "%s::%s::%s" % (namespace_as_string,
-                                                    class_name, method_name) %}
+                                                    class_name, method.name) %}
   {{interface_macros.trace_event("param_", method.parameters,
                                  qualified_method_name)}}
 #endif
@@ -163,7 +163,7 @@
     {{interface_macros.declare_request_params("in_", method)}}) {
 #if BUILDFLAG(MOJO_TRACE_ENABLED)
 {%- set qualified_method_name = "%s::%s::%s" % (namespace_as_string, class_name,
-                                                method_name) %}
+                                                method.name) %}
   {{interface_macros.trace_event("in_", method.parameters,
                                  qualified_method_name)}}
 #endif
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
index 8e64300b..0b415c2 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
@@ -24,8 +24,7 @@
 {%-   endif -%}
 {%- endmacro -%}
 
-{%- macro trace_event(prefix, method_parameters, qualified_method_name,
-                      value="input_params_for_tracing") -%}
+{%- macro trace_event(prefix, method_parameters, qualified_method_name) -%}
 {#- This macro assumes that the argument names are the ones declared by -#}
 {#- |declare_request_params|. Namely the |prefix| should be the same here as -#}
 {#- in |declare_request_params|. -#}
@@ -33,15 +32,17 @@
   TRACE_EVENT1(
     "mojom", "{{qualified_method_name}}", "input_parameters",
     [&](){
-      auto {{value}} = std::make_unique<base::trace_event::TracedValue>();
+      auto value = std::make_unique<base::trace_event::TracedValue>();
+      base::trace_event::TracedValue* raw_value = value.get();
 {%-     for param in method_parameters %}
-{%-       for line in param.kind|write_input_param_for_tracing(prefix,
-                                                               param.name,
-                                                               value) %}
+{%-       for line in param.kind|write_input_param_for_tracing(
+                                   parameter_name=param.name,
+                                   cpp_parameter_name=prefix+param.name,
+                                   value='raw_value') %}
       {{line}}
 {%-       endfor -%}
 {%-     endfor %}
-      return {{value}};
+      return value;
     }());
 {%-   else -%}
   TRACE_EVENT0("mojom", "{{qualified_method_name}}");
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
index 0679323..0bb970e 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
@@ -128,6 +128,19 @@
   {{type}} {{name}};
 {%- endfor %}
 
+#if BUILDFLAG(MOJO_TRACE_ENABLED)
+  // Write this structure into |value|. The members are represented as a
+  // dictionary |member name|: |member value|.
+  //
+  // |value| The TracedValue to be written into.
+  // |parameter_name| Name of the variable holding this structure,
+  //   used as the name of the dictionary representing this structure.
+  //   If nullptr, then the dictionary representing this structure has no name
+  //   (used in arrays of structures).
+  void ToTracedValue(base::trace_event::TracedValue* value,
+    const char* parameter_name = nullptr);
+#endif  // BUILDFLAG(MOJO_TRACE_ENABLED)
+
  private:
   static bool Validate(const void* data,
                        mojo::internal::ValidationContext* validation_context);
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl
index d65dd69..fe9aeada 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl
@@ -32,6 +32,26 @@
 }
 {%- endif %}
 
+#if BUILDFLAG(MOJO_TRACE_ENABLED)
+void {{struct.name}}::ToTracedValue(base::trace_event::TracedValue* value,
+    const char* parameter_name) {
+  if (parameter_name) {
+    value->BeginDictionary(parameter_name);
+  } else {
+    value->BeginDictionary();
+  }
+{%-  for field in struct.fields %}
+{%-    for line in field.kind|write_input_param_for_tracing(
+                                parameter_name=field.name,
+                                cpp_parameter_name='this->'+field.name,
+                                value='value') %}
+  {{line}}
+{%-    endfor -%}
+{%-  endfor %}
+  value->EndDictionary();
+}
+#endif  // BUILDFLAG(MOJO_TRACE_ENABLED)
+
 bool {{struct.name}}::Validate(
     const void* data,
     mojo::internal::ValidationContext* validation_context) {
diff --git a/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.cc.tmpl b/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.cc.tmpl
index e946228..e64615ed 100644
--- a/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.cc.tmpl
+++ b/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.cc.tmpl
@@ -70,23 +70,10 @@
 {%-   set mojom_type = interface|get_qualified_name_for_kind(flatten_nested_kind=True) %}
 {%-   set proto_type = "::mojolpm" ~ (interface|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
 class {{interface.name}}Impl : public {{mojom_type}} {
-  ::mojo::BindingSet<{{mojom_type}}> bindings_;
-  ::mojo::AssociatedBindingSet<{{mojom_type}}> associated_bindings_;
-
  public:
   {{interface.name}}Impl() {
   }
 
-  void Bind({{mojom_type}}Request&& request) {
-    DCHECK(mojolpm::GetContext()->task_runner()->RunsTasksInCurrentSequence());
-    bindings_.AddBinding(this, std::move(request));
-  }
-
-  void Bind({{mojom_type}}AssociatedRequest&& request) {
-    DCHECK(mojolpm::GetContext()->task_runner()->RunsTasksInCurrentSequence());
-    associated_bindings_.AddBinding(this, std::move(request));
-  }
-
 {%-   for method in interface.methods -%}{{"\n"}}
   void {{method.name}}({{ "\n" }}
 {%-     for param in method.parameters -%}
@@ -158,146 +145,6 @@
 {%-   endfor %}
 };
 
-bool FromProto(const {{proto_type}}::Ptr& input,
-               {{mojom_type}}PtrInfo& output) {
-  bool result = false;
-  std::unique_ptr<{{mojom_type}}Ptr> output_ptr = nullptr;
-
-  if (input.id()) {
-    output_ptr = mojolpm::GetContext()->GetAndRemoveInstance<{{mojom_type}}Ptr>(input.id());
-  } else {
-    output_ptr = NewInstance<{{mojom_type}}>();
-  }
-
-  if (output_ptr) {
-    // NB: PassInterface is allowed, since output_ptr is bound on this sequence
-    // (the fuzzer sequence)
-    output = output_ptr.release()->PassInterface();
-    result = true;
-  } else {
-    // we otherwise create a local instance
-    ::mojo::InterfacePtr<{{mojom_type}}> ptr;
-    ::mojo::InterfaceRequest<{{mojom_type}}> request = ::mojo::MakeRequest(&ptr);
-    auto impl = std::make_unique<{{interface.name}}Impl>();
-    impl->Bind(std::move(request));
-    mojolpm::GetContext()->AddInstance(std::move(impl));
-    output = ptr.PassInterface();
-    result = true;
-  }
-
-  return result;
-}
-
-bool FromProto(const {{proto_type}}::AssociatedPtr& input,
-               {{mojom_type}}AssociatedPtrInfo& output) {
-  bool result = false;
-  std::unique_ptr<{{mojom_type}}AssociatedPtr> output_ptr;
-
-  if (input.id()) {
-    output_ptr = mojolpm::GetContext()->GetAndRemoveInstance<{{mojom_type}}AssociatedPtr>(input.id());
-  } else {
-    output_ptr = NewAssociatedInstance<{{mojom_type}}>();
-  }
-
-  if (output_ptr) {
-    // NB: PassInterface is allowed, since output_ptr is bound on this sequence
-    // (the fuzzer sequence)
-    output = output_ptr.release()->PassInterface();
-    result = true;
-  } else {
-    // we otherwise create a local instance
-    ::mojo::AssociatedInterfacePtr<{{mojom_type}}> ptr;
-    ::mojo::AssociatedInterfaceRequest<{{mojom_type}}> request = ::mojo::MakeRequest(&ptr);
-    auto impl = std::make_unique<{{interface.name}}Impl>();
-    impl->Bind(std::move(request));
-    mojolpm::GetContext()->AddInstance(std::move(impl));
-    output = ptr.PassInterface();
-    result = true;
-  }
-
-  return result;
-}
-
-bool FromProto(const {{proto_type}}::Request& input,
-               {{mojom_type}}Request& output) {
-  {{mojom_type}}Ptr ptr;
-
-  output = ::mojo::MakeRequest(&ptr);
-  mojolpm::GetContext()->AddInstance(input.id(), std::move(ptr));
-
-  return true;
-}
-
-bool FromProto(const {{proto_type}}::AssociatedRequest& input,
-               {{mojom_type}}AssociatedRequest& output) {
-  {{mojom_type}}AssociatedPtr ptr;
-
-  output = ::mojo::MakeRequest(&ptr);
-  mojolpm::GetContext()->AddInstance(input.id(), std::move(ptr));
-
-  return true;
-}
-
-bool ToProto({{mojom_type}}PtrInfo&& input,
-             {{proto_type}}::Ptr& output) {
-  bool result = false;
-
-  // NB: Not implementing this at present as it only has limited applicability,
-  // and the corresponding types are being deprecated. If your target needs this
-  // to fuzz effectively, consider porting to the new mojo types.
-  NOTREACHED();
-
-  return result;
-}
-
-bool ToProto({{mojom_type}}Ptr&& input,
-             {{proto_type}}::Ptr& output) {
-  bool result = false;
-
-  // NB: Not implementing this at present as it only has limited applicability,
-  // and the corresponding types are being deprecated. If your target needs this
-  // to fuzz effectively, consider porting to the new mojo types.
-  CHECK(false);
-
-  return result;
-}
-
-bool ToProto({{mojom_type}}AssociatedPtrInfo&& input,
-             {{proto_type}}::AssociatedPtr& output) {
-  bool result = false;
-
-  // NB: Not implementing this at present as it only has limited applicability,
-  // and the corresponding types are being deprecated. If your target needs this
-  // to fuzz effectively, consider porting to the new mojo types.
-  CHECK(false);
-
-  return result;
-}
-
-bool ToProto({{mojom_type}}Request&& input,
-             {{proto_type}}::Request& output) {
-  bool result = false;
-
-  // NB: Not implementing this at present as it only has limited applicability,
-  // and the corresponding types are being deprecated. If your target needs this
-  // to fuzz effectively, consider porting to the new mojo types.
-  CHECK(false);
-
-  return result;
-}
-
-bool ToProto({{mojom_type}}AssociatedRequest&& input,
-             {{proto_type}}::AssociatedRequest& output) {
-  bool result = false;
-
-  // NB: Not implementing this at present as it only has limited applicability,
-  // and the corresponding types are being deprecated. If your target needs this
-  // to fuzz effectively, consider porting to the new mojo types.
-  CHECK(false);
-
-  return result;
-}
-
 bool FromProto(const {{proto_type}}::PendingRemote& input,
                ::mojo::PendingRemote<{{mojom_type}}>& output) {
   bool result = false;
@@ -477,69 +324,6 @@
 {%-   set mojom_type = interface|get_qualified_name_for_kind(flatten_nested_kind=True) %}
 {%-   set proto_type = "::mojolpm" ~ (interface|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
 {%-   if interface.methods %}
-bool HandleMethodCall(const {{proto_type}}::MethodCall& input) {
-  bool result = false;
-
-  //mojolpmdbg("HandleMethodCall({{interface.name}})\n");
-
-  {{mojom_type}}Ptr* instance_ptr;
-  instance_ptr = mojolpm::GetContext()->GetInstance<{{mojom_type}}Ptr>(input.ptr().id());
-
-  if (instance_ptr && *instance_ptr) {
-    result = true;
-  }
-
-  if (result) {
-    switch (input.method_case()) {
-{%-     for method in interface.methods %}
-      case {{proto_type}}::MethodCall::k{{("m_" ~ method.name)|under_to_camel(digits_split=True)}}: {
-        result = HandleMethodCall(*instance_ptr, input.{{("m" ~ method.name)|camel_to_under}}());
-      } break;
-{%-     endfor %}
-case {{proto_type}}::MethodCall::kReset: {
-        mojolpm::GetContext()->GetAndRemoveInstance<{{mojom_type}}Ptr>(input.ptr().id());
-      } break;
-      default: {
-        result = false;
-      }
-    }
-  }
-
-  return result;
-}
-
-bool HandleMethodCallA(const {{proto_type}}::MethodCallA& input) {
-  bool result = false;
-
-  //mojolpmdbg("HandleMethodCall({{interface.name}})\n");
-
-  {{mojom_type}}AssociatedPtr* instance_ptr;
-  instance_ptr = mojolpm::GetContext()->GetInstance<{{mojom_type}}AssociatedPtr>(input.ptr().id());
-
-  if (instance_ptr && instance_ptr->is_bound() && *instance_ptr) {
-    result = true;
-  }
-
-  if (result) {
-    switch (input.method_case()) {
-{%-     for method in interface.methods %}
-      case {{proto_type}}::MethodCallA::k{{("m_" ~ method.name)|under_to_camel(digits_split=True)}}: {
-        result = HandleMethodCallA(*instance_ptr, input.{{("m" ~ method.name)|camel_to_under}}());
-      } break;
-{%-     endfor %}
-      case {{proto_type}}::MethodCallA::kReset: {
-        mojolpm::GetContext()->GetAndRemoveInstance<{{mojom_type}}AssociatedPtr>(input.ptr().id());
-      } break;
-
-      default: {
-        result = false;
-      }
-    }
-  }
-
-  return result;
-}
-
 bool HandleRemoteMethodCall(const {{proto_type}}::RemoteMethodCall& input) {
   bool result = false;
 
@@ -639,102 +423,6 @@
   mojolpm::GetContext()->NextAction();
 }{{"\n"-}}
 {%-       endif %}
-bool HandleMethodCall({{mojom_type}}Ptr& instance,
-                      const {{proto_type}}::{{interface.name}}_{{method.name}}& input) {
-  bool mojolpm_result = true;
-  mojolpmdbg("HandleMethodCall({{interface.name}}::{{method.name}})\n");
-{%-       for param in method.parameters %}
-{%-         set name = param.name|camel_to_under %}
-{%-         set kind = param.kind %}
-{%-         set param_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
-{%-         set param_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=True) %}
-  {{param_mojom_type}} local_{{name}};
-{%-         if kind|is_nullable_kind %}
-  {{param_maybe_mojom_type}} local_maybe_{{name}};
-{%-         endif %}
-{%-       endfor %}
-
-{%-       for param in method.parameters -%}
-{%-         set name = param.name|camel_to_under %}
-{%-         set kind = param.kind %}
-{%-         if not kind|is_nullable_kind %}
-  mojolpm_result &= FromProto(input.m_{{name}}(), local_{{name}});
-  mojolpmdbg("{{name}} %i\n", mojolpm_result);
-{%-         else %}
-  if (FromProto(input.m_{{name}}(), local_maybe_{{name}})) {
-    local_{{name}} = std::move(local_maybe_{{name}});
-  }
-{%-         endif %}
-{%-       endfor %}
-  if (mojolpm_result) {
-    instance->{{method.name}}(
-{%-       for param in method.parameters -%}
-{%-         set name = param.name|camel_to_under %}
-{%-         set kind = param.kind %}
-{%-         if kind|is_interface_kind or kind|is_associated_kind %}
-      {{kind|cpp_wrapper_param_type(add_same_module_namespaces=true)}}(std::move(local_{{name}})){{ ',' if not loop.last }}
-{%-         else %}
-      std::move(local_{{name}}){{ ',' if not loop.last }}
-{%-         endif %}
-{%-       endfor -%}
-{%-       if method.response_parameters != None -%}
-{{ ',' if method.parameters }}
-      base::BindOnce(&{{interface.name}}_{{method.name}}Callback));
-  }
-{%-       else -%}
-);
-  }
-{%-       endif %}
-  return mojolpm_result;
-}
-
-bool HandleMethodCallA({{mojom_type}}AssociatedPtr& instance,
-                       const {{proto_type}}::{{interface.name}}_{{method.name}}& input) {
-  bool mojolpm_result = true;
-  mojolpmdbg("HandleMethodCallA({{interface.name}}::{{method.name}})\n");
-{%-       for param in method.parameters %}
-{%-         set name = param.name|camel_to_under %}
-{%-         set kind = param.kind %}
-{%-         set param_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
-{%-         set param_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=True) %}
-  {{param_mojom_type}} local_{{name}};
-{%-         if kind|is_nullable_kind %}
-  {{param_maybe_mojom_type}} local_maybe_{{name}};
-{%-         endif %}
-{%-       endfor %}
-
-{%-       for param in method.parameters -%}
-{%-         set name = param.name|camel_to_under %}
-{%-         set kind = param.kind %}
-{%-         if not kind|is_nullable_kind %}
-  mojolpm_result &= FromProto(input.m_{{name}}(), local_{{name}});
-{%-         else %}
-  if (FromProto(input.m_{{name}}(), local_maybe_{{name}})) {
-    local_{{name}} = std::move(local_maybe_{{name}});
-  }
-{%-         endif %}
-{%-       endfor %}
-  if (mojolpm_result) {
-    instance->{{method.name}}(
-{%-       for param in method.parameters -%}
-{%-         set name = param.name|camel_to_under %}
-{%-         set kind = param.kind %}
-{%-         if kind|is_interface_kind or kind|is_associated_kind %}
-      {{kind|cpp_wrapper_param_type(add_same_module_namespaces=true)}}(std::move(local_{{name}})){{ ',' if not loop.last }}
-{%-         else %}
-      std::move(local_{{name}}){{ ',' if not loop.last }}
-{%-         endif %}
-{%-       endfor -%}
-{%-       if method.response_parameters != None -%}
-{{ ',' if method.parameters }}
-      base::BindOnce(&{{interface.name}}_{{method.name}}Callback));
-  }
-{%-       else -%}
-);
-  }
-{%-       endif %}
-  return mojolpm_result;
-}
 bool HandleRemoteMethodCall(::mojo::Remote<{{mojom_type}}>& instance,
                             const {{proto_type}}::{{interface.name}}_{{method.name}}& input) {
   bool mojolpm_result = true;
@@ -766,11 +454,7 @@
 {%-       for param in method.parameters -%}
 {%-         set name = param.name|camel_to_under %}
 {%-         set kind = param.kind %}
-{%-         if kind|is_interface_kind or kind|is_associated_kind %}
-      {{kind|cpp_wrapper_param_type(add_same_module_namespaces=true)}}(std::move(local_{{name}})){{ ',' if not loop.last }}
-{%-         else %}
       std::move(local_{{name}}){{ ',' if not loop.last }}
-{%-         endif %}
 {%-       endfor -%}
 {%-       if method.response_parameters != None -%}
 {{ ',' if method.parameters }}
@@ -817,11 +501,7 @@
 {%-       for param in method.parameters -%}
 {%-         set name = param.name|camel_to_under %}
 {%-         set kind = param.kind %}
-{%-         if kind|is_interface_kind or kind|is_associated_kind %}
-      {{kind|cpp_wrapper_param_type(add_same_module_namespaces=true)}}(std::move(local_{{name}})){{ ',' if not loop.last }}
-{%-         else %}
       std::move(local_{{name}}){{ ',' if not loop.last }}
-{%-         endif %}
 {%-       endfor -%}
 {%-       if method.response_parameters != None -%}
 {{ ',' if method.parameters }}
diff --git a/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.h.tmpl b/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.h.tmpl
index 16af070..20ebd05 100644
--- a/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.h.tmpl
+++ b/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.h.tmpl
@@ -117,42 +117,6 @@
 {%-   set proto_type = "::mojolpm" ~ (interface|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
 // interface {{interface.name}}
 bool FromProto(
-  const {{proto_type}}::Ptr& input,
-  {{mojom_type}}PtrInfo& output);
-
-bool ToProto(
-  {{mojom_type}}Ptr&& input,
-  {{proto_type}}::Ptr& output);
-
-bool ToProto(
-  {{mojom_type}}PtrInfo&& input,
-  {{proto_type}}::Ptr& output);
-
-bool FromProto(
-  const {{proto_type}}::AssociatedPtr& input,
-  {{mojom_type}}AssociatedPtrInfo& output);
-
-bool ToProto(
-  {{mojom_type}}AssociatedPtrInfo&& input,
-  {{proto_type}}::AssociatedPtr& output);
-
-bool FromProto(
-  const {{proto_type}}::Request& input,
-  {{mojom_type}}Request& output);
-
-bool ToProto(
-  {{mojom_type}}Request&& input,
-  {{proto_type}}::Request& output);
-
-bool FromProto(
-  const {{proto_type}}::AssociatedRequest& input,
-  {{mojom_type}}AssociatedRequest& output);
-
-bool ToProto(
-  {{mojom_type}}AssociatedRequest&& input,
-  {{proto_type}}::AssociatedRequest& output);
-
-bool FromProto(
   const {{proto_type}}::PendingRemote& input,
   ::mojo::PendingRemote<{{mojom_type}}>& output);
 
@@ -213,12 +177,6 @@
 {%-   set mojom_type = interface|get_qualified_name_for_kind(flatten_nested_kind=True) %}
 {%-   set proto_type = "::mojolpm" ~ (interface|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
 {%-   if interface.methods %}
-bool HandleMethodCall(
-  const {{proto_type}}::MethodCall& input);
-
-bool HandleMethodCallA(
-  const {{proto_type}}::MethodCallA& input);
-
 bool HandleRemoteMethodCall(
   const {{proto_type}}::RemoteMethodCall& input);
 
@@ -228,14 +186,6 @@
 bool AddResponse(
   const {{proto_type}}::ReceiverResponse& response);{{"\n"-}}
 {%-     for method in interface.methods %}
-bool HandleMethodCall(
-  {{mojom_type}}Ptr& instance,
-  const {{proto_type}}::{{interface.name}}_{{method.name}}& input);
-
-bool HandleMethodCallA(
-  {{mojom_type}}AssociatedPtr& instance,
-  const {{proto_type}}::{{interface.name}}_{{method.name}}& input);
-
 bool HandleRemoteMethodCall(
   ::mojo::Remote<{{mojom_type}}>& instance,
   const {{proto_type}}::{{interface.name}}_{{method.name}}& input);
diff --git a/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.proto.tmpl b/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.proto.tmpl
index 521cdf4..0bd0c05 100644
--- a/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.proto.tmpl
+++ b/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm.proto.tmpl
@@ -229,23 +229,6 @@
 {%- for interface in interfaces %}
 
 message {{interface.name}} {
-  // TODO(markbrand): remove the old types once crbug/955171 is landed.
-  message Ptr {
-    required uint32 id = 1;
-  }
-
-  message AssociatedPtr {
-    required uint32 id = 1;
-  }
-
-  message Request {
-    required uint32 id = 1;
-  }
-
-  message AssociatedRequest {
-    required uint32 id = 1;
-  }
-
   message PendingRemote {
     required uint32 id = 1;
   }
@@ -349,28 +332,6 @@
 {%-   endfor%}
 
 {%-   if interface.methods|length %}
-  message MethodCall {
-    required {{interface.name}}.Ptr ptr = 1;
-
-    oneof method {
-      Reset reset = 2;
-{%-     for method in interface.methods %}
-      {{interface.name}}_{{method.name}} m_{{method.name|camel_to_under}} = {{loop.index + 2}};
-{%-     endfor %}
-    }
-  }
-
-  message MethodCallA {
-    required {{interface.name}}.AssociatedPtr ptr = 1;
-
-    oneof method {
-      Reset reset = 2;
-{%-     for method in interface.methods %}
-      {{interface.name}}_{{method.name}} m_{{method.name|camel_to_under}} = {{loop.index + 2}};
-{%-     endfor %}
-    }
-  }
-
   message RemoteMethodCall {
     required {{interface.name}}.PendingRemote remote = 1;
 
diff --git a/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_macros.tmpl b/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_macros.tmpl
index c34ddb3..82d677e 100644
--- a/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_macros.tmpl
@@ -30,18 +30,6 @@
 {{ add_instance(kind.key_kind, name ~ "_key", True)|indent(2, True) }}
 {{ add_instance(kind.value_kind, name ~ "_value", True)|indent(2, True) }}
   }
-{%-   elif kind|is_interface_kind %}
-{%-     set mojom_type = kind|get_qualified_name_for_kind(flatten_nested_kind=True) %}
-  if ({{name}}) {
-    {{mojom_type}}Ptr tmp_{{name}}(std::move({{name}}));
-    mojolpm::GetContext()->AddInstance(std::move(tmp_{{name}}));
-  }
-{%-   elif kind|is_associated_interface_kind %}
-{%-     set mojom_type = kind.kind|get_qualified_name_for_kind(flatten_nested_kind=True) %}
-  if ({{name}}) {
-    {{mojom_type}}AssociatedPtr tmp_{{name}}(std::move({{name}}));
-    mojolpm::GetContext()->AddInstance(std::move(tmp_{{name}}));
-  }
 {%-   elif kind|is_pending_remote_kind %}
 {%-     set mojom_type = kind.kind|get_qualified_name_for_kind(flatten_nested_kind=True) %}
   if ({{name}}) {
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
index 5ec78a7..a756278 100644
--- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -670,22 +670,21 @@
         GetCppPodType(constant.kind), constant.name,
         self._ConstantValue(constant))
 
-  def _WriteInputParamForTracing(self, kind, mojo_prefix, parameter_name,
+  def _WriteInputParamForTracing(self, kind, parameter_name, cpp_parameter_name,
                                  value):
     """Generates lines of C++ to log parameter |parameter_name| into TracedValue
     |value|.
 
     Args:
       kind: {Kind} The kind of the parameter (corresponds to its C++ type).
-      mojo_prefix: {string} The prefix of the auto-generated parameter.
-      parameter_name: {string} The mojom parameter name to be logged
-        (auto-generated C++ parameter name is |mojo_prefix+parameter_name|).
+      parameter_name: {string} The name of the mojom parameter to be logged.
+      cpp_parameter_name: {string} The actual C++ variable name corresponding to
+        the mojom parameter |parameter_name|.
       value: {string} The C++ TracedValue* variable name to be logged into.
 
     Yields:
       {string} C++ lines of code that trace |parameter_name| into |value|.
     """
-    cpp_parameter_name = mojo_prefix + parameter_name
     value_name_cppname = (value, parameter_name, cpp_parameter_name)
     # TODO(crbug.com/1103623): Support more involved types.
     if mojom.IsEnumKind(kind):
@@ -729,6 +728,15 @@
     if mojom.IsFloatKind(kind) or mojom.IsDoubleKind(kind):
       yield '%s->SetDouble("%s", %s);' % value_name_cppname
       return
+    if (mojom.IsStructKind(kind) and not self._IsTypemappedKind(kind)
+        and not IsNativeOnlyKind(kind)):
+      yield 'if (%s.is_null()) {' % cpp_parameter_name
+      yield '  %s->SetString("%s", "nullptr");' % (value, parameter_name)
+      yield '} else {'
+      yield '  %s->ToTracedValue(%s, "%s");' % (cpp_parameter_name, value,
+                                                parameter_name)
+      yield '}'
+      return
     yield '%s->SetString("%s", "<value of type %s>");' % (
         value, parameter_name, self._GetCppWrapperParamType(kind))
 
diff --git a/mojo/public/tools/bindings/generators/mojom_mojolpm_generator.py b/mojo/public/tools/bindings/generators/mojom_mojolpm_generator.py
index 557488fe..af2e1d02 100644
--- a/mojo/public/tools/bindings/generators/mojom_mojolpm_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_mojolpm_generator.py
@@ -346,18 +346,6 @@
         or mojom.IsUnionKind(kind)):
       return self._GetCppProtoNameForKind(
           kind, add_same_module_namespaces=add_same_module_namespaces)
-    elif mojom.IsInterfaceKind(kind):
-      return '%s::Ptr' % self._GetCppProtoNameForKind(
-          kind, add_same_module_namespaces=add_same_module_namespaces)
-    elif mojom.IsInterfaceRequestKind(kind):
-      return '%s::Request' % self._GetCppProtoNameForKind(
-          kind.kind, add_same_module_namespaces=add_same_module_namespaces)
-    elif mojom.IsAssociatedInterfaceKind(kind):
-      return '%s::AssociatedPtr' % self._GetCppProtoNameForKind(
-          kind.kind, add_same_module_namespaces=add_same_module_namespaces)
-    elif mojom.IsAssociatedInterfaceRequestKind(kind):
-      return '%s::AssociatedRequest' % self._GetCppProtoNameForKind(
-          kind.kind, add_same_module_namespaces=add_same_module_namespaces)
     elif mojom.IsPendingRemoteKind(kind):
       return "%s::PendingRemote" % self._GetCppProtoNameForKind(
           kind.kind, add_same_module_namespaces=add_same_module_namespaces)
@@ -403,15 +391,6 @@
       return ("map<%sKey, %sValue>" %
               (self._GetProtoFieldType(kind.key_kind, quantified=False),
                self._GetProtoFieldType(kind.value_kind, quantified=False)))
-    elif mojom.IsInterfaceKind(kind):
-      unquantified = "%s.Ptr" % self._GetProtoNameForKind(kind)
-    elif mojom.IsInterfaceRequestKind(kind):
-      unquantified = "%s.Request" % self._GetProtoNameForKind(kind.kind)
-    elif mojom.IsAssociatedInterfaceKind(kind):
-      unquantified = "%s.AssociatedPtr" % self._GetProtoNameForKind(kind.kind)
-    elif mojom.IsAssociatedInterfaceRequestKind(kind):
-      unquantified = ("%s.AssociatedRequest" %
-                      self._GetProtoNameForKind(kind.kind))
     elif mojom.IsPendingRemoteKind(kind):
       unquantified = "%s.PendingRemote" % self._GetProtoNameForKind(kind.kind)
     elif mojom.IsPendingReceiverKind(kind):
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 7f03585..21f7e12 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -5,6 +5,7 @@
 #include "services/network/network_context.h"
 
 #include <memory>
+#include <string>
 #include <utility>
 
 #include "base/barrier_closure.h"
@@ -1723,6 +1724,41 @@
     std::move(callback).Run(base::nullopt);
 }
 
+#if defined(OS_CHROMEOS)
+void NetworkContext::LookupProxyAuthCredentials(
+    const net::ProxyServer& proxy_server,
+    const std::string& auth_scheme,
+    const std::string& realm,
+    LookupProxyAuthCredentialsCallback callback) {
+  net::HttpAuth::Scheme net_scheme =
+      net::HttpAuth::StringToScheme(base::ToLowerASCII(auth_scheme));
+  if (net_scheme == net::HttpAuth::Scheme::AUTH_SCHEME_MAX) {
+    std::move(callback).Run(base::nullopt);
+    return;
+  }
+  net::HttpAuthCache* http_auth_cache =
+      url_request_context_->http_transaction_factory()
+          ->GetSession()
+          ->http_auth_cache();
+  const char* scheme = proxy_server.is_https() ? "https://" : "http://";
+  GURL proxy_url(scheme + proxy_server.host_port_pair().ToString());
+  if (!proxy_url.is_valid()) {
+    std::move(callback).Run(base::nullopt);
+    return;
+  }
+
+  //  Unlike server credentials, proxy credentials are not keyed on
+  //  NetworkIsolationKey.
+  net::HttpAuthCache::Entry* entry =
+      http_auth_cache->Lookup(proxy_url, net::HttpAuth::AUTH_PROXY, realm,
+                              net_scheme, net::NetworkIsolationKey());
+  if (entry)
+    std::move(callback).Run(entry->credentials());
+  else
+    std::move(callback).Run(base::nullopt);
+}
+#endif
+
 const net::HttpAuthPreferences* NetworkContext::GetHttpAuthPreferences() const {
   return &http_auth_merged_preferences_;
 }
diff --git a/services/network/network_context.h b/services/network/network_context.h
index 325f447..411d99ea 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -407,6 +407,13 @@
       const GURL& url,
       const net::NetworkIsolationKey& network_isolation_key,
       LookupServerBasicAuthCredentialsCallback callback) override;
+#if defined(OS_CHROMEOS)
+  void LookupProxyAuthCredentials(
+      const net::ProxyServer& proxy_server,
+      const std::string& auth_scheme,
+      const std::string& realm,
+      LookupProxyAuthCredentialsCallback callback) override;
+#endif
   void GetOriginPolicyManager(
       mojo::PendingReceiver<mojom::OriginPolicyManager> receiver) override;
 
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index ca1f1bd..782b059 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -1905,6 +1905,116 @@
   EXPECT_FALSE(result.has_value());
 }
 
+#if defined(OS_CHROMEOS)
+base::Optional<net::AuthCredentials> GetProxyAuthCredentials(
+    NetworkContext* network_context,
+    const net::ProxyServer& proxy_server,
+    const std::string& scheme,
+    const std::string& realm) {
+  base::RunLoop run_loop;
+  base::Optional<net::AuthCredentials> result;
+  network_context->LookupProxyAuthCredentials(
+      proxy_server, scheme, realm,
+      base::BindLambdaForTesting(
+          [&](const base::Optional<net::AuthCredentials>& credentials) {
+            result = credentials;
+            run_loop.Quit();
+          }));
+  run_loop.Run();
+  return result;
+}
+
+TEST_F(NetworkContextTest, LookupProxyAuthCredentials) {
+  GURL http_proxy("http://bar.test:1080");
+  GURL https_proxy("https://bar.test:443");
+  GURL http_proxy2("http://bar.test:443");
+  GURL foo_proxy("foo://bar.test:1080");
+  GURL server_origin("http://foo.test:3128");
+
+  std::unique_ptr<NetworkContext> network_context =
+      CreateContextWithParams(CreateContextParams());
+  network_context->SetSplitAuthCacheByNetworkIsolationKey(true);
+  net::HttpAuthCache* cache = network_context->url_request_context()
+                                  ->http_transaction_factory()
+                                  ->GetSession()
+                                  ->http_auth_cache();
+
+  base::string16 user = base::ASCIIToUTF16("user");
+  base::string16 password = base::ASCIIToUTF16("pass");
+  cache->Add(http_proxy, net::HttpAuth::AUTH_PROXY, "Realm",
+             net::HttpAuth::AUTH_SCHEME_BASIC, net::NetworkIsolationKey(),
+             "basic realm=Realm", net::AuthCredentials(user, password),
+             /* path = */ "");
+  cache->Add(https_proxy, net::HttpAuth::AUTH_PROXY, "Realm",
+             net::HttpAuth::AUTH_SCHEME_BASIC, net::NetworkIsolationKey(),
+             "basic realm=Realm", net::AuthCredentials(user, password),
+             /* path = */ "");
+  cache->Add(server_origin, net::HttpAuth::AUTH_SERVER, "Realm",
+             net::HttpAuth::AUTH_SCHEME_BASIC, net::NetworkIsolationKey(),
+             "basic realm=Realm", net::AuthCredentials(user, password),
+             /* path = */ "/");
+  base::Optional<net::AuthCredentials> result = GetProxyAuthCredentials(
+      network_context.get(),
+      net::ProxyServer(net::ProxyServer::Scheme::SCHEME_HTTP,
+                       net::HostPortPair::FromURL(http_proxy)),
+      "bAsIc", "Realm");
+  ASSERT_TRUE(result.has_value());
+  EXPECT_EQ(user, result->username());
+  EXPECT_EQ(password, result->password());
+
+  result = GetProxyAuthCredentials(
+      network_context.get(),
+      net::ProxyServer(net::ProxyServer::Scheme::SCHEME_HTTPS,
+                       net::HostPortPair::FromURL(https_proxy)),
+      "bAsIc", "Realm");
+  ASSERT_TRUE(result.has_value());
+  EXPECT_EQ(user, result->username());
+  EXPECT_EQ(password, result->password());
+
+  // Check that the proxy scheme is taken into account when looking for
+  // credentials
+  result = GetProxyAuthCredentials(
+      network_context.get(),
+      net::ProxyServer(net::ProxyServer::Scheme::SCHEME_HTTP,
+                       net::HostPortPair::FromURL(http_proxy2)),
+      "basic", "Realm");
+  EXPECT_FALSE(result.has_value());
+
+  // Check that the proxy authentication method is taken into account when
+  // looking for credentials
+  result = GetProxyAuthCredentials(
+      network_context.get(),
+      net::ProxyServer(net::ProxyServer::Scheme::SCHEME_HTTP,
+                       net::HostPortPair::FromURL(http_proxy)),
+      "digest", "Realm");
+  EXPECT_FALSE(result.has_value());
+
+  // Check that the realm is taken into account when looking for credentials
+  result = GetProxyAuthCredentials(
+      network_context.get(),
+      net::ProxyServer(net::ProxyServer::Scheme::SCHEME_HTTP,
+                       net::HostPortPair::FromURL(http_proxy)),
+      "basic", "Realm 2");
+  EXPECT_FALSE(result.has_value());
+
+  // All non-https proxies are cached as "http://" proxies
+  result = GetProxyAuthCredentials(
+      network_context.get(),
+      net::ProxyServer(net::ProxyServer::Scheme::SCHEME_HTTP,
+                       net::HostPortPair::FromURL(foo_proxy)),
+      "basic", "Realm");
+  EXPECT_FALSE(result.has_value());
+
+  // Server credentials should not be returned
+  result = GetProxyAuthCredentials(
+      network_context.get(),
+      net::ProxyServer(net::ProxyServer::Scheme::SCHEME_HTTP,
+                       net::HostPortPair::FromURL(server_origin)),
+      "basic", "Realm");
+  EXPECT_FALSE(result.has_value());
+}
+#endif
+
 #if BUILDFLAG(ENABLE_REPORTING)
 TEST_F(NetworkContextTest, ClearReportingCacheReports) {
   auto reporting_context = std::make_unique<net::TestReportingContext>(
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 2c696bb..e0aab3e 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -1376,6 +1376,16 @@
       NetworkIsolationKey network_isolation_key)
       => (AuthCredentials? credentials);
 
+  // Looks up the proxy authentication credentials associated with
+  // |proxy_server|, |auth_scheme| and |realm| in the HttpAuthCache.
+  // |auth_scheme| is the authentication scheme of the challenge and it's
+  // specified as a case-insensitive string. Unlike server credentials, proxy
+  // credentials are not keyed on NetworkIsolationKey.
+  [EnableIf=is_chromeos]
+  LookupProxyAuthCredentials(proxy_resolver.mojom.ProxyServer proxy_server,
+      string auth_scheme, string realm)
+      => (AuthCredentials? credentials);
+
   [Sync]
   // Enables the checking of static PKP records.
   EnableStaticKeyPinningForTesting() => ();
diff --git a/services/network/test/test_network_context.h b/services/network/test/test_network_context.h
index ef97b4c..0dfed1a7 100644
--- a/services/network/test/test_network_context.h
+++ b/services/network/test/test_network_context.h
@@ -264,6 +264,13 @@
       const GURL& url,
       const net::NetworkIsolationKey& network_isolation_key,
       LookupServerBasicAuthCredentialsCallback callback) override {}
+#if defined(OS_CHROMEOS)
+  void LookupProxyAuthCredentials(
+      const net::ProxyServer& proxy_server,
+      const std::string& auth_scheme,
+      const std::string& realm,
+      LookupProxyAuthCredentialsCallback callback) override {}
+#endif
   void GetOriginPolicyManager(
       mojo::PendingReceiver<mojom::OriginPolicyManager> receiver) override {}
 };
diff --git a/storage/browser/quota/padding_key.cc b/storage/browser/quota/padding_key.cc
index 60c3b60..788f6f4 100644
--- a/storage/browser/quota/padding_key.cc
+++ b/storage/browser/quota/padding_key.cc
@@ -9,6 +9,7 @@
 
 #include "base/no_destructor.h"
 #include "crypto/hmac.h"
+#include "net/http/http_request_headers.h"
 
 using crypto::SymmetricKey;
 
@@ -57,7 +58,8 @@
 int64_t ComputeResponsePadding(const std::string& response_url,
                                const crypto::SymmetricKey* padding_key,
                                bool has_metadata,
-                               bool loaded_with_credentials) {
+                               bool loaded_with_credentials,
+                               const std::string& request_method) {
   DCHECK(!response_url.empty());
 
   crypto::HMAC hmac(crypto::HMAC::SHA256);
@@ -68,6 +70,14 @@
     key += "METADATA";
   if (loaded_with_credentials)
     key += "CREDENTIALED";
+
+  // It should only be possible to have a CORS safelisted method here since
+  // the spec does not permit other methods for no-cors requests.
+  DCHECK(request_method == net::HttpRequestHeaders::kGetMethod ||
+         request_method == net::HttpRequestHeaders::kHeadMethod ||
+         request_method == net::HttpRequestHeaders::kPostMethod);
+  key += request_method;
+
   uint64_t digest_start;
   CHECK(hmac.Sign(key, reinterpret_cast<uint8_t*>(&digest_start),
                   sizeof(digest_start)));
diff --git a/storage/browser/quota/padding_key.h b/storage/browser/quota/padding_key.h
index e582b4c9..4b5978a 100644
--- a/storage/browser/quota/padding_key.h
+++ b/storage/browser/quota/padding_key.h
@@ -62,7 +62,8 @@
 int64_t ComputeResponsePadding(const std::string& response_url,
                                const crypto::SymmetricKey* padding_key,
                                bool has_metadata,
-                               bool loaded_with_credentials);
+                               bool loaded_with_credentials,
+                               const std::string& request_method);
 
 }  // namespace storage
 
diff --git a/testing/buildbot/filters/bfcache.content_browsertests.filter b/testing/buildbot/filters/bfcache.content_browsertests.filter
index 25c0268..74c7098 100644
--- a/testing/buildbot/filters/bfcache.content_browsertests.filter
+++ b/testing/buildbot/filters/bfcache.content_browsertests.filter
@@ -53,3 +53,4 @@
 -RenderFrameHostImplBeforeUnloadBrowserTest.SubframeShowsDialogWhenMainFrameNavigates
 -RenderFrameHostImplBrowserTest.CheckIsCurrentBeforeAndAfterUnload
 -RenderFrameHostImplBrowserTest.CheckLifecycleStateTransitionOnMainFrame
+-SecurityExploitBrowserTest.DidCommitInvalidURL
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn
index 1960b2e..18c6e2f 100644
--- a/third_party/blink/public/mojom/BUILD.gn
+++ b/third_party/blink/public/mojom/BUILD.gn
@@ -85,12 +85,15 @@
     "loader/request_context_frame_type.mojom",
     "loader/resource_load_info.mojom",
     "loader/resource_load_info_notifier.mojom",
+    "loader/transferrable_url_loader.mojom",
     "loader/url_loader_factory_bundle.mojom",
     "locks/lock_manager.mojom",
     "manifest/display_mode.mojom",
     "manifest/manifest.mojom",
     "manifest/manifest_manager.mojom",
     "manifest/manifest_observer.mojom",
+    "media/renderer_audio_input_stream_factory.mojom",
+    "media/renderer_audio_output_stream_factory.mojom",
     "mediastream/aec_dump.mojom",
     "mediastream/media_devices.mojom",
     "mediastream/media_stream.mojom",
diff --git a/third_party/blink/public/mojom/fetch/fetch_api_response.mojom b/third_party/blink/public/mojom/fetch/fetch_api_response.mojom
index ec7f275..b4e4b9a 100644
--- a/third_party/blink/public/mojom/fetch/fetch_api_response.mojom
+++ b/third_party/blink/public/mojom/fetch/fetch_api_response.mojom
@@ -46,6 +46,10 @@
   // The mime type of the response, if one has been set.
   string? mime_type;
 
+  // The http request method used to load the response.  May be unset for
+  // synthetic Response objects created via the constructor.
+  string? request_method;
+
   // Mojo interface to read the response payload.
   SerializedBlob? blob;
 
diff --git a/third_party/blink/public/mojom/hid/hid.mojom b/third_party/blink/public/mojom/hid/hid.mojom
index 75272a0..bb68311d 100644
--- a/third_party/blink/public/mojom/hid/hid.mojom
+++ b/third_party/blink/public/mojom/hid/hid.mojom
@@ -73,7 +73,7 @@
 interface HidService {
   // Registers a HidManagerClient to be notified when HID devices are added or
   // removed.
-  RegisterClient(associated device.mojom.HidManagerClient client);
+  RegisterClient(pending_associated_remote<device.mojom.HidManagerClient> client);
 
   // Retrieves information about all devices that this client has permission to
   // access.
diff --git a/content/public/common/transferrable_url_loader.mojom b/third_party/blink/public/mojom/loader/transferrable_url_loader.mojom
similarity index 96%
rename from content/public/common/transferrable_url_loader.mojom
rename to third_party/blink/public/mojom/loader/transferrable_url_loader.mojom
index af3adc71..4c5c4d95 100644
--- a/content/public/common/transferrable_url_loader.mojom
+++ b/third_party/blink/public/mojom/loader/transferrable_url_loader.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module content.mojom;
+module blink.mojom;
 
 import "services/network/public/mojom/url_response_head.mojom";
 import "services/network/public/mojom/url_loader.mojom";
diff --git a/third_party/blink/public/mojom/media/OWNERS b/third_party/blink/public/mojom/media/OWNERS
new file mode 100644
index 0000000..94ab98ba
--- /dev/null
+++ b/third_party/blink/public/mojom/media/OWNERS
@@ -0,0 +1,4 @@
+file://content/common/media/OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/content/common/media/renderer_audio_input_stream_factory.mojom b/third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom
similarity index 98%
rename from content/common/media/renderer_audio_input_stream_factory.mojom
rename to third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom
index 361de5d0..9713cd2f 100644
--- a/content/common/media/renderer_audio_input_stream_factory.mojom
+++ b/third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module content.mojom;
+module blink.mojom;
 
 import "media/mojo/mojom/audio_data_pipe.mojom";
 import "media/mojo/mojom/audio_input_stream.mojom";
diff --git a/content/common/media/renderer_audio_output_stream_factory.mojom b/third_party/blink/public/mojom/media/renderer_audio_output_stream_factory.mojom
similarity index 98%
rename from content/common/media/renderer_audio_output_stream_factory.mojom
rename to third_party/blink/public/mojom/media/renderer_audio_output_stream_factory.mojom
index c151fec4..92cb788 100644
--- a/content/common/media/renderer_audio_output_stream_factory.mojom
+++ b/third_party/blink/public/mojom/media/renderer_audio_output_stream_factory.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module content.mojom;
+module blink.mojom;
 
 import "media/mojo/mojom/audio_output_stream.mojom";
 import "media/mojo/mojom/audio_parameters.mojom";
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index 576af16c..f6fb128 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2546,7 +2546,6 @@
   kLegacyLayoutByFlexBox = 3210,
   kLegacyLayoutByFrameSet = 3211,
   kLegacyLayoutByGrid = 3212,
-  kLegacyLayoutByMenuList = 3213,
   kLegacyLayoutByMultiCol = 3214,
   kLegacyLayoutByPrinting = 3215,
   kLegacyLayoutByRuby = 3216,
diff --git a/third_party/blink/public/web/web_ax_object.h b/third_party/blink/public/web/web_ax_object.h
index b9bf20f29..72e328c1 100644
--- a/third_party/blink/public/web/web_ax_object.h
+++ b/third_party/blink/public/web/web_ax_object.h
@@ -191,7 +191,7 @@
   BLINK_EXPORT ax::mojom::Role Role() const;
   BLINK_EXPORT WebString StringValue() const;
   BLINK_EXPORT ax::mojom::ListStyle GetListStyle() const;
-  BLINK_EXPORT ax::mojom::TextDirection GetTextDirection() const;
+  BLINK_EXPORT ax::mojom::WritingDirection GetTextDirection() const;
   BLINK_EXPORT ax::mojom::TextPosition GetTextPosition() const;
   BLINK_EXPORT void GetTextStyleAndTextDecorationStyle(
       int32_t* text_style,
diff --git a/third_party/blink/renderer/core/css/css_variable_data.cc b/third_party/blink/renderer/core/css/css_variable_data.cc
index 303a387c..03e2a89 100644
--- a/third_party/blink/renderer/core/css/css_variable_data.cc
+++ b/third_party/blink/renderer/core/css/css_variable_data.cc
@@ -83,7 +83,6 @@
       needs_variable_resolution_(needs_variable_resolution),
       has_font_units_(false),
       has_root_font_units_(false),
-      absolutized_(false),
       base_url_(base_url.IsValid() ? base_url.GetString() : String()),
       charset_(charset) {
   DCHECK(!range.AtEnd());
diff --git a/third_party/blink/renderer/core/css/css_variable_data.h b/third_party/blink/renderer/core/css/css_variable_data.h
index 70df8fc..d225dff 100644
--- a/third_party/blink/renderer/core/css/css_variable_data.h
+++ b/third_party/blink/renderer/core/css/css_variable_data.h
@@ -38,17 +38,17 @@
   }
 
   static scoped_refptr<CSSVariableData> CreateResolved(
-      const Vector<CSSParserToken>& resolved_tokens,
+      Vector<CSSParserToken> resolved_tokens,
       Vector<String> backing_strings,
       bool is_animation_tainted,
       bool has_font_units,
       bool has_root_font_units,
-      bool absolutized,
       const String& base_url,
       const WTF::TextEncoding& charset) {
     return base::AdoptRef(new CSSVariableData(
-        resolved_tokens, std::move(backing_strings), is_animation_tainted,
-        has_font_units, has_root_font_units, absolutized, base_url, charset));
+        std::move(resolved_tokens), std::move(backing_strings),
+        is_animation_tainted, has_font_units, has_root_font_units, base_url,
+        charset));
   }
 
   CSSParserTokenRange TokenRange() const { return tokens_; }
@@ -70,10 +70,6 @@
   // font-size of the root element, e.g. 'rem'.
   bool HasRootFontUnits() const { return has_root_font_units_; }
 
-  // True if this CSSVariableData has undergone absolutization. Absolutization
-  // is required for e.g. registered properties with 'em' units.
-  bool IsAbsolutized() const { return absolutized_; }
-
   const String& BaseURL() const { return base_url_; }
 
   const WTF::TextEncoding& Charset() const { return charset_; }
@@ -86,8 +82,7 @@
       : is_animation_tainted_(false),
         needs_variable_resolution_(false),
         has_font_units_(false),
-        has_root_font_units_(false),
-        absolutized_(false) {}
+        has_root_font_units_(false) {}
 
   CSSVariableData(const CSSParserTokenRange&,
                   bool is_animation_tainted,
@@ -95,21 +90,19 @@
                   const KURL& base_url,
                   const WTF::TextEncoding& charset);
 
-  CSSVariableData(const Vector<CSSParserToken>& resolved_tokens,
+  CSSVariableData(Vector<CSSParserToken> resolved_tokens,
                   Vector<String> backing_strings,
                   bool is_animation_tainted,
                   bool has_font_units,
                   bool has_root_font_units,
-                  bool absolutized,
                   const String& base_url,
                   const WTF::TextEncoding& charset)
       : backing_strings_(std::move(backing_strings)),
-        tokens_(resolved_tokens),
+        tokens_(std::move(resolved_tokens)),
         is_animation_tainted_(is_animation_tainted),
         needs_variable_resolution_(false),
         has_font_units_(has_font_units),
         has_root_font_units_(has_root_font_units),
-        absolutized_(absolutized),
         base_url_(base_url),
         charset_(charset) {}
 
@@ -124,7 +117,6 @@
   const bool needs_variable_resolution_;
   bool has_font_units_;
   bool has_root_font_units_;
-  bool absolutized_;
   String base_url_;
   WTF::TextEncoding charset_;
   DISALLOW_COPY_AND_ASSIGN(CSSVariableData);
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index ca33486..82de618 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -1974,11 +1974,10 @@
 
   const bool has_font_units = false;
   const bool has_root_font_units = false;
-  const bool absolutized = true;
 
   return CSSVariableData::CreateResolved(
-      tokens, std::move(backing_strings), is_animation_tainted, has_font_units,
-      has_root_font_units, absolutized, g_null_atom, WTF::TextEncoding());
+      std::move(tokens), std::move(backing_strings), is_animation_tainted,
+      has_font_units, has_root_font_units, g_null_atom, WTF::TextEncoding());
 }
 
 LengthSize StyleBuilderConverter::ConvertIntrinsicSize(
diff --git a/third_party/blink/renderer/core/css/resolver/style_cascade.cc b/third_party/blink/renderer/core/css/resolver/style_cascade.cc
index a17473e..fca76ca 100644
--- a/third_party/blink/renderer/core/css/resolver/style_cascade.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_cascade.cc
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/core/css/style_engine.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/core/style_property_shorthand.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
@@ -227,6 +228,8 @@
       map_.Add(property.GetCSSPropertyName(), e.Priority());
     }
   }
+
+  MaybeUseCountSummaryDisplayBlock();
 }
 
 void StyleCascade::AnalyzeInterpolations() {
@@ -530,11 +533,9 @@
 
 scoped_refptr<CSSVariableData>
 StyleCascade::TokenSequence::BuildVariableData() {
-  // TODO(andruud): Why not also std::move tokens?
-  const bool absolutized = true;
   return CSSVariableData::CreateResolved(
-      tokens_, std::move(backing_strings_), is_animation_tainted_,
-      has_font_units_, has_root_font_units_, absolutized, base_url_, charset_);
+      std::move(tokens_), std::move(backing_strings_), is_animation_tainted_,
+      has_font_units_, has_root_font_units_, base_url_, charset_);
 }
 
 bool StyleCascade::ShouldRevert(const CSSProperty& property,
@@ -700,11 +701,7 @@
                                             const CSSValue& value,
                                             CascadeOrigin origin,
                                             CascadeResolver& resolver) {
-  // In forced colors mode, we can behave like 'revert' any value [1], but we
-  // should only use-count the true uses of 'revert'.
-  // [1] https://drafts.csswg.org/css-color-adjust-1/#forced-colors-properties
-  if (IsRevert(value))
-    GetDocument().CountUse(WebFeature::kCSSKeywordRevert);
+  MaybeUseCountRevert(value);
 
   CascadeOrigin target_origin = TargetOriginForRevert(origin);
 
@@ -931,4 +928,30 @@
   return *original;
 }
 
+void StyleCascade::CountUse(WebFeature feature) {
+  GetDocument().CountUse(feature);
+}
+
+void StyleCascade::MaybeUseCountRevert(const CSSValue& value) {
+  // In forced colors mode, any value can behave like 'revert' [1], but we
+  // should only use-count the true uses of 'revert'.
+  // [1] https://drafts.csswg.org/css-color-adjust-1/#forced-colors-properties
+  if (IsRevert(value))
+    CountUse(WebFeature::kCSSKeywordRevert);
+}
+
+// TODO(crbug.com/590014): Remove this when display type of <summary> is fixed
+void StyleCascade::MaybeUseCountSummaryDisplayBlock() {
+  if (!state_.GetElement().HasTagName(html_names::kSummaryTag))
+    return;
+  CascadePriority priority = map_.At(CSSPropertyName(CSSPropertyID::kDisplay));
+  if (priority.GetOrigin() == CascadeOrigin::kUserAgent)
+    return;
+  const CSSValue* value = ValueAt(match_result_, priority.GetPosition());
+  if (auto* identifier = DynamicTo<CSSIdentifierValue>(value)) {
+    if (identifier->GetValueID() == CSSValueID::kBlock)
+      CountUse(WebFeature::kSummaryElementWithDisplayBlockAuthorRule);
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/resolver/style_cascade.h b/third_party/blink/renderer/core/css/resolver/style_cascade.h
index e9be592..a8e6d7b 100644
--- a/third_party/blink/renderer/core/css/resolver/style_cascade.h
+++ b/third_party/blink/renderer/core/css/resolver/style_cascade.h
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/core/css/resolver/cascade_origin.h"
 #include "third_party/blink/renderer/core/css/resolver/cascade_priority.h"
 #include "third_party/blink/renderer/core/css/resolver/match_result.h"
+#include "third_party/blink/renderer/core/frame/web_feature_forward.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -324,6 +325,10 @@
 
   bool ShouldRevert(const CSSProperty&, const CSSValue&, CascadeOrigin);
 
+  void CountUse(WebFeature);
+  void MaybeUseCountRevert(const CSSValue&);
+  void MaybeUseCountSummaryDisplayBlock();
+
   StyleResolverState& state_;
   MatchResult match_result_;
   CascadeInterpolations interpolations_;
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index 6f7c1f3..11c32674 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -948,22 +948,6 @@
     MatchAllRules(state, collector,
                   matching_behavior != kMatchAllRulesExcludingSMIL);
 
-    // TODO(dominicc): Remove this counter when Issue 590014 is fixed.
-    if (element->HasTagName(html_names::kSummaryTag)) {
-      MatchedPropertiesRange matched_range = match_result.AuthorRules();
-      for (const auto& matched : matched_range) {
-        const CSSValue* value =
-            matched.properties->GetPropertyCSSValue(CSSPropertyID::kDisplay);
-        auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
-        if (identifier_value &&
-            identifier_value->GetValueID() == CSSValueID::kBlock) {
-          UseCounter::Count(
-              element->GetDocument(),
-              WebFeature::kSummaryElementWithDisplayBlockAuthorRule);
-        }
-      }
-    }
-
     if (tracker_)
       AddMatchedRulesToTracker(collector);
 
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc
index 1b13af30..f39b209 100644
--- a/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -2698,6 +2698,29 @@
                                     GetCSSPropertyColor()));
 }
 
+TEST_F(StyleEngineTest, SummaryDisplayUseCount) {
+  // Should not be use-counted: wrong element type.
+  GetDocument().body()->setInnerHTML(
+      "<style>div { display: block; }</style><div></div>");
+  UpdateAllLifecyclePhases();
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kSummaryElementWithDisplayBlockAuthorRule));
+
+  // Should not be use-counted: wrong display type:
+  GetDocument().body()->setInnerHTML(
+      "<style>summary { display: inline; }</style><summary></summary>");
+  UpdateAllLifecyclePhases();
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kSummaryElementWithDisplayBlockAuthorRule));
+
+  // Should be use-counted:
+  GetDocument().body()->setInnerHTML(
+      "<style>summary { display: block; }</style><summary></summary>");
+  UpdateAllLifecyclePhases();
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kSummaryElementWithDisplayBlockAuthorRule));
+}
+
 TEST_F(StyleEngineTest, RevertUseCount) {
   ScopedCSSRevertForTest scoped_feature(true);
 
diff --git a/third_party/blink/renderer/core/css/style_environment_variables.cc b/third_party/blink/renderer/core/css/style_environment_variables.cc
index d1e3e8e..1a7404f 100644
--- a/third_party/blink/renderer/core/css/style_environment_variables.cc
+++ b/third_party/blink/renderer/core/css/style_environment_variables.cc
@@ -149,11 +149,12 @@
   Vector<String> backing_strings;
   backing_strings.push_back(value);
 
-  SetVariable(name,
-              CSSVariableData::CreateResolved(
-                  tokens, backing_strings, false /* is_animation_tainted */,
-                  false /* has_font_units */, false /* has_root_font_units*/,
-                  true /* absolutized */, g_null_atom, WTF::TextEncoding()));
+  SetVariable(
+      name,
+      CSSVariableData::CreateResolved(
+          std::move(tokens), std::move(backing_strings),
+          false /* is_animation_tainted */, false /* has_font_units */,
+          false /* has_root_font_units*/, g_null_atom, WTF::TextEncoding()));
 }
 
 void StyleEnvironmentVariables::SetVariable(const UADefinedVariable name,
diff --git a/third_party/blink/renderer/core/editing/BUILD.gn b/third_party/blink/renderer/core/editing/BUILD.gn
index 829afcf..31fbacd 100644
--- a/third_party/blink/renderer/core/editing/BUILD.gn
+++ b/third_party/blink/renderer/core/editing/BUILD.gn
@@ -336,7 +336,6 @@
     "visible_units_paragraph.cc",
     "visible_units_sentence.cc",
     "visible_units_word.cc",
-    "writing_direction.h",
   ]
 
   if (is_mac) {
diff --git a/third_party/blink/renderer/core/editing/commands/apply_style_command.cc b/third_party/blink/renderer/core/editing/commands/apply_style_command.cc
index 151283c..f41b19e5 100644
--- a/third_party/blink/renderer/core/editing/commands/apply_style_command.cc
+++ b/third_party/blink/renderer/core/editing/commands/apply_style_command.cc
@@ -48,7 +48,6 @@
 #include "third_party/blink/renderer/core/editing/visible_position.h"
 #include "third_party/blink/renderer/core/editing/visible_selection.h"
 #include "third_party/blink/renderer/core/editing/visible_units.h"
-#include "third_party/blink/renderer/core/editing/writing_direction.h"
 #include "third_party/blink/renderer/core/html/html_font_element.h"
 #include "third_party/blink/renderer/core/html/html_span_element.h"
 #include "third_party/blink/renderer/core/html_names.h"
@@ -566,7 +565,7 @@
 HTMLElement* ApplyStyleCommand::SplitAncestorsWithUnicodeBidi(
     Node* node,
     bool before,
-    WritingDirection allowed_direction) {
+    mojo_base::mojom::blink::TextDirection allowed_direction) {
   // We are allowed to leave the highest ancestor with unicode-bidi unsplit if
   // it is unicode-bidi: embed and direction: allowedDirection. In that case, we
   // return the unsplit ancestor. Otherwise, we return 0.
@@ -597,10 +596,11 @@
 
   HTMLElement* unsplit_ancestor = nullptr;
 
-  WritingDirection highest_ancestor_direction;
+  mojo_base::mojom::blink::TextDirection highest_ancestor_direction;
   auto* highest_ancestor_html_element =
       DynamicTo<HTMLElement>(highest_ancestor_with_unicode_bidi);
-  if (allowed_direction != WritingDirection::kNatural &&
+  if (allowed_direction !=
+          mojo_base::mojom::blink::TextDirection::UNKNOWN_DIRECTION &&
       highest_ancestor_unicode_bidi != CSSValueID::kBidiOverride &&
       highest_ancestor_html_element &&
       MakeGarbageCollected<EditingStyle>(highest_ancestor_with_unicode_bidi,
@@ -750,7 +750,8 @@
   // selection and prevent us from adding redundant ones, as described in:
   // <rdar://problem/3724344> Bolding and unbolding creates extraneous tags
   Position remove_start = MostBackwardCaretPosition(start);
-  WritingDirection text_direction = WritingDirection::kNatural;
+  mojo_base::mojom::blink::TextDirection text_direction =
+      mojo_base::mojom::blink::TextDirection::UNKNOWN_DIRECTION;
   bool has_text_direction = style->GetTextDirection(text_direction);
   EditingStyle* style_without_embedding = nullptr;
   EditingStyle* embedding_style = nullptr;
diff --git a/third_party/blink/renderer/core/editing/commands/apply_style_command.h b/third_party/blink/renderer/core/editing/commands/apply_style_command.h
index daa86e763..d0170d6 100644
--- a/third_party/blink/renderer/core/editing/commands/apply_style_command.h
+++ b/third_party/blink/renderer/core/editing/commands/apply_style_command.h
@@ -37,8 +37,6 @@
 
 enum ShouldIncludeTypingStyle { kIncludeTypingStyle, kIgnoreTypingStyle };
 
-enum class WritingDirection;
-
 class CORE_EXPORT ApplyStyleCommand final : public CompositeEditCommand {
  public:
   enum PropertyLevel { kPropertyDefault, kForceBlockProperties };
@@ -160,7 +158,7 @@
   HTMLElement* SplitAncestorsWithUnicodeBidi(
       Node*,
       bool before,
-      WritingDirection allowed_direction);
+      mojo_base::mojom::blink::TextDirection allowed_direction);
   void RemoveEmbeddingUpToEnclosingBlock(Node*,
                                          HTMLElement* unsplit_ancestor,
                                          EditingState*);
diff --git a/third_party/blink/renderer/core/editing/commands/style_commands.cc b/third_party/blink/renderer/core/editing/commands/style_commands.cc
index 84c26596..c0136e7 100644
--- a/third_party/blink/renderer/core/editing/commands/style_commands.cc
+++ b/third_party/blink/renderer/core/editing/commands/style_commands.cc
@@ -44,7 +44,6 @@
 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/editing/visible_position.h"
-#include "third_party/blink/renderer/core/editing/writing_direction.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/html/html_font_element.h"
@@ -417,20 +416,20 @@
          value_id == CSSValueID::kPlaintext;
 }
 
-WritingDirection StyleCommands::TextDirectionForSelection(
+mojo_base::mojom::blink::TextDirection StyleCommands::TextDirectionForSelection(
     const VisibleSelection& selection,
     EditingStyle* typing_style,
     bool& has_nested_or_multiple_embeddings) {
   has_nested_or_multiple_embeddings = true;
 
   if (selection.IsNone())
-    return WritingDirection::kNatural;
+    return mojo_base::mojom::blink::TextDirection::UNKNOWN_DIRECTION;
 
   const Position position = MostForwardCaretPosition(selection.Start());
 
   const Node* anchor_node = position.AnchorNode();
   if (!anchor_node)
-    return WritingDirection::kNatural;
+    return mojo_base::mojom::blink::TextDirection::UNKNOWN_DIRECTION;
 
   Position end;
   if (selection.IsRange()) {
@@ -455,12 +454,12 @@
       const CSSValueID unicode_bidi_value =
           unicode_bidi_identifier_value->GetValueID();
       if (IsUnicodeBidiNestedOrMultipleEmbeddings(unicode_bidi_value))
-        return WritingDirection::kNatural;
+        return mojo_base::mojom::blink::TextDirection::UNKNOWN_DIRECTION;
     }
   }
 
   if (selection.IsCaret()) {
-    WritingDirection direction;
+    mojo_base::mojom::blink::TextDirection direction;
     if (typing_style && typing_style->GetTextDirection(direction)) {
       has_nested_or_multiple_embeddings = false;
       return direction;
@@ -472,7 +471,8 @@
   // The selection is either a caret with no typing attributes or a range in
   // which no embedding is added, so just use the start position to decide.
   const Node* block = EnclosingBlock(anchor_node);
-  WritingDirection found_direction = WritingDirection::kNatural;
+  mojo_base::mojom::blink::TextDirection found_direction =
+      mojo_base::mojom::blink::TextDirection::UNKNOWN_DIRECTION;
 
   for (Node& runner : NodeTraversal::InclusiveAncestorsOf(*anchor_node)) {
     if (runner == block)
@@ -496,7 +496,7 @@
       continue;
 
     if (unicode_bidi_value == CSSValueID::kBidiOverride)
-      return WritingDirection::kNatural;
+      return mojo_base::mojom::blink::TextDirection::UNKNOWN_DIRECTION;
 
     DCHECK(EditingStyleUtilities::IsEmbedOrIsolate(unicode_bidi_value))
         << static_cast<int>(unicode_bidi_value);
@@ -511,17 +511,19 @@
         direction_value != CSSValueID::kRtl)
       continue;
 
-    if (found_direction != WritingDirection::kNatural)
-      return WritingDirection::kNatural;
+    if (found_direction !=
+        mojo_base::mojom::blink::TextDirection::UNKNOWN_DIRECTION)
+      return mojo_base::mojom::blink::TextDirection::UNKNOWN_DIRECTION;
 
     // In the range case, make sure that the embedding element persists until
     // the end of the range.
     if (selection.IsRange() && !end.AnchorNode()->IsDescendantOf(element))
-      return WritingDirection::kNatural;
+      return mojo_base::mojom::blink::TextDirection::UNKNOWN_DIRECTION;
 
-    found_direction = direction_value == CSSValueID::kLtr
-                          ? WritingDirection::kLeftToRight
-                          : WritingDirection::kRightToLeft;
+    found_direction =
+        direction_value == CSSValueID::kLtr
+            ? mojo_base::mojom::blink::TextDirection::LEFT_TO_RIGHT
+            : mojo_base::mojom::blink::TextDirection::RIGHT_TO_LEFT;
   }
   has_nested_or_multiple_embeddings = false;
   return found_direction;
@@ -529,13 +531,14 @@
 
 EditingTriState StyleCommands::StateTextWritingDirection(
     LocalFrame& frame,
-    WritingDirection direction) {
+    mojo_base::mojom::blink::TextDirection direction) {
   frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
 
   bool has_nested_or_multiple_embeddings;
-  WritingDirection selection_direction = TextDirectionForSelection(
-      frame.Selection().ComputeVisibleSelectionInDOMTreeDeprecated(),
-      frame.GetEditor().TypingStyle(), has_nested_or_multiple_embeddings);
+  mojo_base::mojom::blink::TextDirection selection_direction =
+      TextDirectionForSelection(
+          frame.Selection().ComputeVisibleSelectionInDOMTreeDeprecated(),
+          frame.GetEditor().TypingStyle(), has_nested_or_multiple_embeddings);
   // TODO(editing-dev): We should be returning MixedTriState when
   // selectionDirection == direction && hasNestedOrMultipleEmbeddings
   return (selection_direction == direction &&
@@ -547,19 +550,22 @@
 EditingTriState StyleCommands::StateTextWritingDirectionLeftToRight(
     LocalFrame& frame,
     Event*) {
-  return StateTextWritingDirection(frame, WritingDirection::kLeftToRight);
+  return StateTextWritingDirection(
+      frame, mojo_base::mojom::blink::TextDirection::LEFT_TO_RIGHT);
 }
 
 EditingTriState StyleCommands::StateTextWritingDirectionNatural(
     LocalFrame& frame,
     Event*) {
-  return StateTextWritingDirection(frame, WritingDirection::kNatural);
+  return StateTextWritingDirection(
+      frame, mojo_base::mojom::blink::TextDirection::UNKNOWN_DIRECTION);
 }
 
 EditingTriState StyleCommands::StateTextWritingDirectionRightToLeft(
     LocalFrame& frame,
     Event*) {
-  return StateTextWritingDirection(frame, WritingDirection::kRightToLeft);
+  return StateTextWritingDirection(
+      frame, mojo_base::mojom::blink::TextDirection::RIGHT_TO_LEFT);
 }
 
 EditingTriState StyleCommands::StateUnderline(LocalFrame& frame, Event*) {
diff --git a/third_party/blink/renderer/core/editing/commands/style_commands.h b/third_party/blink/renderer/core/editing/commands/style_commands.h
index 0400ca2..4728106 100644
--- a/third_party/blink/renderer/core/editing/commands/style_commands.h
+++ b/third_party/blink/renderer/core/editing/commands/style_commands.h
@@ -46,7 +46,6 @@
 
 enum class EditingTriState;
 enum class EditorCommandSource;
-enum class WritingDirection;
 
 // This class provides static functions about commands related to style.
 class StyleCommands {
@@ -203,11 +202,11 @@
 
   // TODO(editing-dev): We should make |textDirectionForSelection()| to take
   // |selectionInDOMTree|.
-  static WritingDirection TextDirectionForSelection(const VisibleSelection&,
-                                                    EditingStyle*,
-                                                    bool&);
-  static EditingTriState StateTextWritingDirection(LocalFrame&,
-                                                   WritingDirection);
+  static mojo_base::mojom::blink::TextDirection
+  TextDirectionForSelection(const VisibleSelection&, EditingStyle*, bool&);
+  static EditingTriState StateTextWritingDirection(
+      LocalFrame&,
+      mojo_base::mojom::blink::TextDirection);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/editing_style.cc b/third_party/blink/renderer/core/editing/editing_style.cc
index 6736935..0dde54d9 100644
--- a/third_party/blink/renderer/core/editing/editing_style.cc
+++ b/third_party/blink/renderer/core/editing/editing_style.cc
@@ -57,7 +57,6 @@
 #include "third_party/blink/renderer/core/editing/position.h"
 #include "third_party/blink/renderer/core/editing/serializers/html_interchange.h"
 #include "third_party/blink/renderer/core/editing/visible_selection.h"
-#include "third_party/blink/renderer/core/editing/writing_direction.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/html/html_font_element.h"
@@ -636,7 +635,8 @@
          font_size_delta_ == kNoFontDelta;
 }
 
-bool EditingStyle::GetTextDirection(WritingDirection& writing_direction) const {
+bool EditingStyle::GetTextDirection(
+    mojo_base::mojom::blink::TextDirection& writing_direction) const {
   if (!mutable_style_)
     return false;
 
@@ -657,14 +657,15 @@
 
     writing_direction =
         direction_identifier_value->GetValueID() == CSSValueID::kLtr
-            ? WritingDirection::kLeftToRight
-            : WritingDirection::kRightToLeft;
+            ? mojo_base::mojom::blink::TextDirection::LEFT_TO_RIGHT
+            : mojo_base::mojom::blink::TextDirection::RIGHT_TO_LEFT;
 
     return true;
   }
 
   if (unicode_bidi_value == CSSValueID::kNormal) {
-    writing_direction = WritingDirection::kNatural;
+    writing_direction =
+        mojo_base::mojom::blink::TextDirection::UNKNOWN_DIRECTION;
     return true;
   }
 
diff --git a/third_party/blink/renderer/core/editing/editing_style.h b/third_party/blink/renderer/core/editing/editing_style.h
index 240cb4bd..08fbbec 100644
--- a/third_party/blink/renderer/core/editing/editing_style.h
+++ b/third_party/blink/renderer/core/editing/editing_style.h
@@ -32,6 +32,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_EDITING_STYLE_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_EDITING_STYLE_H_
 
+#include "mojo/public/mojom/base/text_direction.mojom-blink-forward.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/css_property_names.h"
 #include "third_party/blink/renderer/core/css_value_keywords.h"
@@ -58,7 +59,6 @@
 class CSSPropertyValueSet;
 enum class EditingTriState;
 enum class SecureContextMode;
-enum class WritingDirection;
 
 class CORE_EXPORT EditingStyle final : public GarbageCollected<EditingStyle> {
  public:
@@ -86,7 +86,7 @@
   EditingStyle(CSSPropertyID, const String& value, SecureContextMode);
 
   MutableCSSPropertyValueSet* Style() { return mutable_style_.Get(); }
-  bool GetTextDirection(WritingDirection&) const;
+  bool GetTextDirection(mojo_base::mojom::blink::TextDirection&) const;
   bool IsEmpty() const;
   void OverrideWithStyle(const CSSPropertyValueSet*);
   void Clear();
diff --git a/third_party/blink/renderer/core/editing/editor.cc b/third_party/blink/renderer/core/editing/editor.cc
index 96dffd1..304e2f10 100644
--- a/third_party/blink/renderer/core/editing/editor.cc
+++ b/third_party/blink/renderer/core/editing/editor.cc
@@ -65,7 +65,6 @@
 #include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h"
 #include "third_party/blink/renderer/core/editing/visible_position.h"
 #include "third_party/blink/renderer/core/editing/visible_units.h"
-#include "third_party/blink/renderer/core/editing/writing_direction.h"
 #include "third_party/blink/renderer/core/events/keyboard_event.h"
 #include "third_party/blink/renderer/core/events/text_event.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -633,14 +632,17 @@
   undo_stack_->Redo();
 }
 
-void Editor::SetBaseWritingDirection(WritingDirection direction) {
+void Editor::SetBaseWritingDirection(
+    mojo_base::mojom::blink::TextDirection direction) {
   Element* focused_element = GetFrame().GetDocument()->FocusedElement();
   if (auto* text_control = ToTextControlOrNull(focused_element)) {
-    if (direction == WritingDirection::kNatural)
+    if (direction == mojo_base::mojom::blink::TextDirection::UNKNOWN_DIRECTION)
       return;
     text_control->setAttribute(
         html_names::kDirAttr,
-        direction == WritingDirection::kLeftToRight ? "ltr" : "rtl");
+        direction == mojo_base::mojom::blink::TextDirection::LEFT_TO_RIGHT
+            ? "ltr"
+            : "rtl");
     text_control->DispatchInputEvent();
     return;
   }
@@ -649,9 +651,11 @@
       MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLQuirksMode);
   style->SetProperty(
       CSSPropertyID::kDirection,
-      direction == WritingDirection::kLeftToRight
+      direction == mojo_base::mojom::blink::TextDirection::LEFT_TO_RIGHT
           ? "ltr"
-          : direction == WritingDirection::kRightToLeft ? "rtl" : "inherit",
+          : direction == mojo_base::mojom::blink::TextDirection::RIGHT_TO_LEFT
+                ? "rtl"
+                : "inherit",
       /* important */ false, GetFrame().DomWindow()->GetSecureContextMode());
   ApplyParagraphStyleToSelection(
       style, InputEvent::InputType::kFormatSetBlockTextDirection);
diff --git a/third_party/blink/renderer/core/editing/editor.h b/third_party/blink/renderer/core/editing/editor.h
index 23acef1..49e938a4 100644
--- a/third_party/blink/renderer/core/editing/editor.h
+++ b/third_party/blink/renderer/core/editing/editor.h
@@ -59,7 +59,6 @@
 enum class DragSourceType { kHTMLSource, kPlainTextSource };
 enum class EditorParagraphSeparator { kIsDiv, kIsP };
 enum class EditorCommandSource { kMenuOrKeyBinding, kDOM };
-enum class WritingDirection;
 
 class CORE_EXPORT Editor final : public GarbageCollected<Editor> {
  public:
@@ -133,7 +132,7 @@
   // Supposed to be used as |const UndoStack&|.
   UndoStack& GetUndoStack() const { return *undo_stack_; }
 
-  void SetBaseWritingDirection(WritingDirection);
+  void SetBaseWritingDirection(mojo_base::mojom::blink::TextDirection);
 
   // smartInsertDeleteEnabled and selectTrailingWhitespaceEnabled are
   // mutually exclusive, meaning that enabling one will disable the other.
diff --git a/third_party/blink/renderer/core/editing/writing_direction.h b/third_party/blink/renderer/core/editing/writing_direction.h
deleted file mode 100644
index af5e583cb9..0000000
--- a/third_party/blink/renderer/core/editing/writing_direction.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_WRITING_DIRECTION_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_WRITING_DIRECTION_H_
-
-namespace blink {
-
-enum class WritingDirection { kNatural, kLeftToRight, kRightToLeft };
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/blink/renderer/core/fetch/fetch_manager.cc b/third_party/blink/renderer/core/fetch/fetch_manager.cc
index bd31c5e..d677de5 100644
--- a/third_party/blink/renderer/core/fetch/fetch_manager.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_manager.cc
@@ -428,7 +428,8 @@
       BodyStreamBuffer::Create(script_state, place_holder_body_, signal_));
 
   response_data->InitFromResourceResponse(
-      url_list_, fetch_request_data_->Credentials(), tainting, response);
+      url_list_, fetch_request_data_->Method(),
+      fetch_request_data_->Credentials(), tainting, response);
 
   FetchResponseData* tainted_response = nullptr;
 
diff --git a/third_party/blink/renderer/core/fetch/fetch_response_data.cc b/third_party/blink/renderer/core/fetch/fetch_response_data.cc
index c595b241..2605dadb 100644
--- a/third_party/blink/renderer/core/fetch/fetch_response_data.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_response_data.cc
@@ -191,6 +191,7 @@
   new_response->status_message_ = status_message_;
   new_response->header_list_ = header_list_->Clone();
   new_response->mime_type_ = mime_type_;
+  new_response->request_method_ = request_method_;
   new_response->response_time_ = response_time_;
   new_response->cache_storage_cache_name_ = cache_storage_cache_name_;
   new_response->cors_exposed_header_names_ = cors_exposed_header_names_;
@@ -262,6 +263,7 @@
   response->response_type = type_;
   response->response_source = response_source_;
   response->mime_type = mime_type_;
+  response->request_method = request_method_;
   response->response_time = response_time_;
   response->cache_storage_cache_name = cache_storage_cache_name_;
   response->cors_exposed_header_names =
@@ -279,6 +281,7 @@
 
 void FetchResponseData::InitFromResourceResponse(
     const Vector<KURL>& request_url_list,
+    const AtomicString& request_method,
     network::mojom::CredentialsMode request_credentials,
     FetchRequestData::Tainting tainting,
     const ResourceResponse& response) {
@@ -308,6 +311,7 @@
   }
 
   SetMimeType(response.MimeType());
+  SetRequestMethod(request_method);
   SetResponseTime(response.ResponseTime());
 
   if (response.WasCached()) {
diff --git a/third_party/blink/renderer/core/fetch/fetch_response_data.h b/third_party/blink/renderer/core/fetch/fetch_response_data.h
index 0c4bfcb..e5c65cc 100644
--- a/third_party/blink/renderer/core/fetch/fetch_response_data.h
+++ b/third_party/blink/renderer/core/fetch/fetch_response_data.h
@@ -95,6 +95,9 @@
     status_message_ = status_message;
   }
   void SetMimeType(const String& type) { mime_type_ = type; }
+  void SetRequestMethod(const AtomicString& method) {
+    request_method_ = method;
+  }
   void SetResponseTime(base::Time response_time) {
     response_time_ = response_time;
   }
@@ -131,6 +134,7 @@
   // Initialize non-body data from the given |response|.
   void InitFromResourceResponse(
       const Vector<KURL>& request_url_list,
+      const AtomicString& request_method,
       network::mojom::CredentialsMode request_credentials,
       FetchRequestData::Tainting tainting,
       const ResourceResponse& response);
@@ -148,6 +152,7 @@
   Member<FetchResponseData> internal_response_;
   Member<BodyStreamBuffer> buffer_;
   String mime_type_;
+  AtomicString request_method_;
   base::Time response_time_;
   String cache_storage_cache_name_;
   HTTPHeaderSet cors_exposed_header_names_;
diff --git a/third_party/blink/renderer/core/fetch/response.cc b/third_party/blink/renderer/core/fetch/response.cc
index 619232c2..a1f5932 100644
--- a/third_party/blink/renderer/core/fetch/response.cc
+++ b/third_party/blink/renderer/core/fetch/response.cc
@@ -378,6 +378,8 @@
   response->SetURLList(fetch_api_response.url_list);
   response->SetStatus(fetch_api_response.status_code);
   response->SetStatusMessage(WTF::AtomicString(fetch_api_response.status_text));
+  response->SetRequestMethod(
+      WTF::AtomicString(fetch_api_response.request_method));
   response->SetResponseTime(fetch_api_response.response_time);
   response->SetCacheStorageCacheName(
       fetch_api_response.cache_storage_cache_name);
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 814e0c05..25a7913 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -91,7 +91,6 @@
 #include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h"
 #include "third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.h"
 #include "third_party/blink/renderer/core/editing/surrounding_text.h"
-#include "third_party/blink/renderer/core/editing/writing_direction.h"
 #include "third_party/blink/renderer/core/execution_context/window_agent.h"
 #include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
 #include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
@@ -803,15 +802,18 @@
 
   switch (direction) {
     case base::i18n::TextDirection::UNKNOWN_DIRECTION:
-      editor.SetBaseWritingDirection(WritingDirection::kNatural);
+      editor.SetBaseWritingDirection(
+          mojo_base::mojom::blink::TextDirection::UNKNOWN_DIRECTION);
       break;
 
     case base::i18n::TextDirection::LEFT_TO_RIGHT:
-      editor.SetBaseWritingDirection(WritingDirection::kLeftToRight);
+      editor.SetBaseWritingDirection(
+          mojo_base::mojom::blink::TextDirection::LEFT_TO_RIGHT);
       break;
 
     case base::i18n::TextDirection::RIGHT_TO_LEFT:
-      editor.SetBaseWritingDirection(WritingDirection::kRightToLeft);
+      editor.SetBaseWritingDirection(
+          mojo_base::mojom::blink::TextDirection::RIGHT_TO_LEFT);
       break;
 
     default:
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
index 2a2048e0..e76085af 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
@@ -1515,12 +1515,6 @@
   }
 }
 
-WebTextInputType WebFrameWidgetBase::TextInputType() {
-  WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
-  if (!focused_frame)
-    return WebTextInputType::kWebTextInputTypeNone;
-  return focused_frame->GetInputMethodController()->TextInputType();
-}
 
 void WebFrameWidgetBase::AddImeTextSpansToExistingText(
     uint32_t start,
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_base.h b/third_party/blink/renderer/core/frame/web_frame_widget_base.h
index acade8a..be7e3d7 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_base.h
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_base.h
@@ -142,7 +142,6 @@
   void GetCompositionCharacterBoundsInWindow(
       Vector<gfx::Rect>* bounds) override;
   gfx::Range CompositionRange() override;
-  WebTextInputType TextInputType() override;
   WebTextInputInfo TextInputInfo() override;
   ui::mojom::VirtualKeyboardVisibilityRequest
   GetLastVirtualKeyboardVisibilityRequest() override;
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index eb55e9f..0863431 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -169,7 +169,6 @@
 #include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h"
 #include "third_party/blink/renderer/core/editing/text_affinity.h"
 #include "third_party/blink/renderer/core/editing/visible_position.h"
-#include "third_party/blink/renderer/core/editing/writing_direction.h"
 #include "third_party/blink/renderer/core/events/after_print_event.h"
 #include "third_party/blink/renderer/core/events/before_print_event.h"
 #include "third_party/blink/renderer/core/exported/local_frame_client_impl.h"
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.cc b/third_party/blink/renderer/core/html/forms/html_select_element.cc
index f34d6c126..e504a3810 100644
--- a/third_party/blink/renderer/core/html/forms/html_select_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_select_element.cc
@@ -44,7 +44,6 @@
 #include "third_party/blink/renderer/core/dom/node_lists_node_data.h"
 #include "third_party/blink/renderer/core/dom/node_traversal.h"
 #include "third_party/blink/renderer/core/events/keyboard_event.h"
-#include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/html/forms/form_controller.h"
 #include "third_party/blink/renderer/core/html/forms/form_data.h"
 #include "third_party/blink/renderer/core/html/forms/html_form_element.h"
@@ -363,14 +362,6 @@
   return !UsesMenuList();
 }
 
-bool HTMLSelectElement::TypeShouldForceLegacyLayout() const {
-  if (!RuntimeEnabledFeatures::LayoutNGForControlsEnabled() && UsesMenuList()) {
-    UseCounter::Count(GetDocument(), WebFeature::kLegacyLayoutByMenuList);
-    return true;
-  }
-  return false;
-}
-
 LayoutObject* HTMLSelectElement::CreateLayoutObject(
     const ComputedStyle& style,
     LegacyLayout legacy_layout) {
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.h b/third_party/blink/renderer/core/html/forms/html_select_element.h
index 86570a1..8e5029a3 100644
--- a/third_party/blink/renderer/core/html/forms/html_select_element.h
+++ b/third_party/blink/renderer/core/html/forms/html_select_element.h
@@ -211,7 +211,6 @@
   void ParseAttribute(const AttributeModificationParams&) override;
   bool IsPresentationAttribute(const QualifiedName&) const override;
 
-  bool TypeShouldForceLegacyLayout() const override;
   LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override;
   void DidRecalcStyle(const StyleRecalcChange) override;
   void AttachLayoutTree(AttachContext&) override;
diff --git a/third_party/blink/renderer/core/inspector/inspect_tools.cc b/third_party/blink/renderer/core/inspector/inspect_tools.cc
index 181cb05..520f770 100644
--- a/third_party/blink/renderer/core/inspector/inspect_tools.cc
+++ b/third_party/blink/renderer/core/inspector/inspect_tools.cc
@@ -227,6 +227,9 @@
 }
 
 bool SearchingForNodeTool::HandlePointerEvent(const WebPointerEvent& event) {
+  // Trigger Inspect only when a pointer device is pressed down.
+  if (event.GetType() != WebInputEvent::Type::kPointerDown)
+    return false;
   Node* node = HoveredNodeForEvent(overlay_->GetFrame(), event, false);
   if (node) {
     overlay_->Inspect(node);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
index 465fe25..ea47434 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
@@ -357,20 +357,23 @@
   const auto* layout_box = ToLayoutBoxOrNull(GetLayoutObject());
   if (UNLIKELY(!layout_box))
     return nullptr;
+  const wtf_size_t fragment_count = layout_box->PhysicalFragmentCount();
+  if (fragment_count == 0) {
+    // This should not happen, but DCHECK hits. crbug.com/1107204
+    return nullptr;
+  }
 
-  DCHECK_GT(layout_box->PhysicalFragmentCount(), 0u);
-  if (layout_box->PhysicalFragmentCount() == 1) {
+  if (fragment_count == 1) {
     const NGPhysicalFragment* post_layout = layout_box->GetPhysicalFragment(0);
     DCHECK(post_layout);
     if (UNLIKELY(post_layout && post_layout != this)) {
-      // Relayout boundary is the only case this can happen. crbug.com/829028
+      // This can happen at the relayout boundary crbug.com/829028
+      // but DCHECKing |IsRelayoutBoundary| hits. crbug.com/1107204
       DCHECK(layout_box->IsRelayoutBoundary());
       return post_layout;
     }
-  } else {
-    // TODO(crbug.com/829028): Block fragmentation not supported yet.
-    DCHECK(!layout_box->IsRelayoutBoundary());
   }
+  // TODO(crbug.com/829028): Block fragmentation not supported yet.
   DCHECK(std::any_of(layout_box->PhysicalFragments().begin(),
                      layout_box->PhysicalFragments().end(),
                      [this](const NGPhysicalFragment& fragment) {
diff --git a/third_party/blink/renderer/core/svg/svg_circle_element.cc b/third_party/blink/renderer/core/svg/svg_circle_element.cc
index b322e86f..f6aaff7 100644
--- a/third_party/blink/renderer/core/svg/svg_circle_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_circle_element.cc
@@ -20,6 +20,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_circle_element.h"
 
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.h"
 #include "third_party/blink/renderer/core/svg/svg_length.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
@@ -62,8 +63,8 @@
   Path path;
 
   SVGLengthContext length_context(this);
-  DCHECK(GetLayoutObject());
-  const ComputedStyle& style = GetLayoutObject()->StyleRef();
+  const ComputedStyle& style = ComputedStyleRef();
+
   const SVGComputedStyle& svg_style = style.SvgStyle();
 
   float r = length_context.ValueForLength(svg_style.R(), style,
diff --git a/third_party/blink/renderer/core/svg/svg_ellipse_element.cc b/third_party/blink/renderer/core/svg/svg_ellipse_element.cc
index a5098d79..f5d6ed2 100644
--- a/third_party/blink/renderer/core/svg/svg_ellipse_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_ellipse_element.cc
@@ -20,6 +20,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_ellipse_element.h"
 
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.h"
 #include "third_party/blink/renderer/core/svg/svg_length.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
@@ -70,8 +71,8 @@
   Path path;
 
   SVGLengthContext length_context(this);
-  DCHECK(GetLayoutObject());
-  const ComputedStyle& style = GetLayoutObject()->StyleRef();
+  const ComputedStyle& style = ComputedStyleRef();
+
   const SVGComputedStyle& svg_style = style.SvgStyle();
 
   FloatSize radii(ToFloatSize(
diff --git a/third_party/blink/renderer/core/svg/svg_geometry_element.cc b/third_party/blink/renderer/core/svg/svg_geometry_element.cc
index 4710421..c7f27292 100644
--- a/third_party/blink/renderer/core/svg/svg_geometry_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_geometry_element.cc
@@ -154,22 +154,36 @@
   return AsPath().length();
 }
 
-SVGPointTearOff* SVGGeometryElement::getPointAtLength(float length) {
+SVGPointTearOff* SVGGeometryElement::getPointAtLength(
+    float length,
+    ExceptionState& exception_state) {
   GetDocument().UpdateStyleAndLayoutForNode(this,
                                             DocumentUpdateReason::kJavaScript);
 
-  FloatPoint point;
-  if (GetLayoutObject()) {
-    const Path& path = AsPath();
-    if (length < 0) {
-      length = 0;
-    } else {
-      float computed_length = path.length();
-      if (length > computed_length)
-        length = computed_length;
-    }
-    point = path.PointAtLength(length);
+  if (!EnsureComputedStyle()) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kInvalidStateError,
+        "The element is in an inactive document.");
+    return nullptr;
   }
+
+  const Path& path = AsPath();
+
+  if (path.IsEmpty()) {
+    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+                                      "The element's path is empty.");
+    return nullptr;
+  }
+
+  if (length < 0) {
+    length = 0;
+  } else {
+    float computed_length = path.length();
+    if (length > computed_length)
+      length = computed_length;
+  }
+  FloatPoint point = path.PointAtLength(length);
+
   return SVGPointTearOff::CreateDetached(point);
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_geometry_element.h b/third_party/blink/renderer/core/svg/svg_geometry_element.h
index 8ec93d84..37607cb 100644
--- a/third_party/blink/renderer/core/svg/svg_geometry_element.h
+++ b/third_party/blink/renderer/core/svg/svg_geometry_element.h
@@ -52,7 +52,7 @@
   SVGAnimatedNumber* pathLength() const { return path_length_.Get(); }
 
   virtual float getTotalLength(ExceptionState&);
-  virtual SVGPointTearOff* getPointAtLength(float distance);
+  virtual SVGPointTearOff* getPointAtLength(float distance, ExceptionState&);
 
   float AuthorPathLength() const;
   float PathLengthScaleFactor() const;
diff --git a/third_party/blink/renderer/core/svg/svg_geometry_element.idl b/third_party/blink/renderer/core/svg/svg_geometry_element.idl
index 4babc7f..02711605 100644
--- a/third_party/blink/renderer/core/svg/svg_geometry_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_geometry_element.idl
@@ -38,5 +38,5 @@
     [HighEntropy, Measure] boolean isPointInFill(SVGPoint point);
     [HighEntropy, Measure] boolean isPointInStroke(SVGPoint point);
     [HighEntropy, Measure, RaisesException] float getTotalLength();
-    [HighEntropy, Measure] SVGPoint getPointAtLength(float distance);
+    [HighEntropy, Measure, RaisesException] SVGPoint getPointAtLength(float distance);
 };
diff --git a/third_party/blink/renderer/core/svg/svg_line_element.cc b/third_party/blink/renderer/core/svg/svg_line_element.cc
index b3013d2..d74a5aab 100644
--- a/third_party/blink/renderer/core/svg/svg_line_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_line_element.cc
@@ -20,6 +20,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_line_element.h"
 
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/svg/svg_length.h"
 #include "third_party/blink/renderer/platform/graphics/path.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
@@ -66,6 +67,8 @@
   Path path;
 
   SVGLengthContext length_context(this);
+  DCHECK(GetComputedStyle());
+
   path.MoveTo(FloatPoint(x1()->CurrentValue()->Value(length_context),
                          y1()->CurrentValue()->Value(length_context)));
   path.AddLineTo(FloatPoint(x2()->CurrentValue()->Value(length_context),
diff --git a/third_party/blink/renderer/core/svg/svg_path_element.cc b/third_party/blink/renderer/core/svg/svg_path_element.cc
index 0a3c9ca..748a3df 100644
--- a/third_party/blink/renderer/core/svg/svg_path_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_path_element.cc
@@ -20,6 +20,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_path_element.h"
 
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/svg/svg_mpath_element.h"
 #include "third_party/blink/renderer/core/svg/svg_path_query.h"
@@ -47,8 +48,8 @@
 }
 
 const StylePath* SVGPathElement::GetStylePath() const {
-  if (LayoutObject* layout_object = GetLayoutObject()) {
-    const StylePath* style_path = layout_object->StyleRef().SvgStyle().D();
+  if (const ComputedStyle* style = GetComputedStyle()) {
+    const StylePath* style_path = style->SvgStyle().D();
     if (style_path)
       return style_path;
     return StylePath::EmptyPath();
@@ -70,10 +71,26 @@
   return SVGPathQuery(PathByteStream()).GetTotalLength();
 }
 
-SVGPointTearOff* SVGPathElement::getPointAtLength(float length) {
+SVGPointTearOff* SVGPathElement::getPointAtLength(
+    float length,
+    ExceptionState& exception_state) {
   GetDocument().UpdateStyleAndLayoutForNode(this,
                                             DocumentUpdateReason::kJavaScript);
-  SVGPathQuery path_query(PathByteStream());
+  if (!EnsureComputedStyle()) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kInvalidStateError,
+        "The element is in an inactive document.");
+    return nullptr;
+  }
+
+  const SVGPathByteStream& byte_stream = PathByteStream();
+  if (byte_stream.IsEmpty()) {
+    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+                                      "The element's path is empty.");
+    return nullptr;
+  }
+
+  SVGPathQuery path_query(byte_stream);
   if (length < 0) {
     length = 0;
   } else {
diff --git a/third_party/blink/renderer/core/svg/svg_path_element.h b/third_party/blink/renderer/core/svg/svg_path_element.h
index babb968..52e61e67 100644
--- a/third_party/blink/renderer/core/svg/svg_path_element.h
+++ b/third_party/blink/renderer/core/svg/svg_path_element.h
@@ -39,7 +39,7 @@
   Path AttributePath() const;
 
   float getTotalLength(ExceptionState&) override;
-  SVGPointTearOff* getPointAtLength(float distance) override;
+  SVGPointTearOff* getPointAtLength(float distance, ExceptionState&) override;
 
   SVGAnimatedPath* GetPath() const { return path_.Get(); }
   float ComputePathLength() const override;
diff --git a/third_party/blink/renderer/core/svg/svg_poly_element.cc b/third_party/blink/renderer/core/svg/svg_poly_element.cc
index d612f35..2aaa9f1 100644
--- a/third_party/blink/renderer/core/svg/svg_poly_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_poly_element.cc
@@ -20,6 +20,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_poly_element.h"
 
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/svg/svg_animated_point_list.h"
 #include "third_party/blink/renderer/platform/graphics/path.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
@@ -43,6 +44,7 @@
 
 Path SVGPolyElement::AsPathFromPoints() const {
   Path path;
+  DCHECK(GetComputedStyle());
 
   const SVGPointList* points_value = Points()->CurrentValue();
   if (points_value->IsEmpty())
diff --git a/third_party/blink/renderer/core/svg/svg_rect_element.cc b/third_party/blink/renderer/core/svg/svg_rect_element.cc
index a98dde36..bb60bab 100644
--- a/third_party/blink/renderer/core/svg/svg_rect_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_rect_element.cc
@@ -20,6 +20,7 @@
 
 #include "third_party/blink/renderer/core/svg/svg_rect_element.h"
 
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_rect.h"
 #include "third_party/blink/renderer/core/svg/svg_length.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
@@ -86,8 +87,7 @@
   Path path;
 
   SVGLengthContext length_context(this);
-  DCHECK(GetLayoutObject());
-  const ComputedStyle& style = GetLayoutObject()->StyleRef();
+  const ComputedStyle& style = ComputedStyleRef();
 
   FloatSize size(ToFloatSize(
       length_context.ResolveLengthPair(style.Width(), style.Height(), style)));
diff --git a/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc b/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc
index 961b69c..30a6442 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.cc
@@ -160,19 +160,19 @@
 
 // In addition to LTR and RTL direction, edit fields also support
 // top to bottom and bottom to top via the CSS writing-mode property.
-ax::mojom::TextDirection AXInlineTextBox::GetTextDirection() const {
+ax::mojom::blink::WritingDirection AXInlineTextBox::GetTextDirection() const {
   if (!inline_text_box_)
     return AXObject::GetTextDirection();
 
   switch (inline_text_box_->GetDirection()) {
     case AbstractInlineTextBox::kLeftToRight:
-      return ax::mojom::TextDirection::kLtr;
+      return ax::mojom::blink::WritingDirection::kLtr;
     case AbstractInlineTextBox::kRightToLeft:
-      return ax::mojom::TextDirection::kRtl;
+      return ax::mojom::blink::WritingDirection::kRtl;
     case AbstractInlineTextBox::kTopToBottom:
-      return ax::mojom::TextDirection::kTtb;
+      return ax::mojom::blink::WritingDirection::kTtb;
     case AbstractInlineTextBox::kBottomToTop:
-      return ax::mojom::TextDirection::kBtt;
+      return ax::mojom::blink::WritingDirection::kBtt;
   }
 
   return AXObject::GetTextDirection();
diff --git a/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h b/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h
index 76af7737..ba665de 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h
@@ -65,7 +65,7 @@
                          SkMatrix44& out_container_transform,
                          bool* clips_children = nullptr) const override;
   AXObject* ComputeParent() const override;
-  ax::mojom::TextDirection GetTextDirection() const override;
+  ax::mojom::blink::WritingDirection GetTextDirection() const override;
   Node* GetNode() const override;
   AXObject* NextOnLine() const override;
   AXObject* PreviousOnLine() const override;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
index a7bb6633..aeac617 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -922,7 +922,7 @@
   return AXNodeObject::GetText();
 }
 
-ax::mojom::blink::TextDirection AXLayoutObject::GetTextDirection() const {
+ax::mojom::blink::WritingDirection AXLayoutObject::GetTextDirection() const {
   if (!GetLayoutObject())
     return AXNodeObject::GetTextDirection();
 
@@ -933,16 +933,16 @@
   if (style->IsHorizontalWritingMode()) {
     switch (style->Direction()) {
       case TextDirection::kLtr:
-        return ax::mojom::blink::TextDirection::kLtr;
+        return ax::mojom::blink::WritingDirection::kLtr;
       case TextDirection::kRtl:
-        return ax::mojom::blink::TextDirection::kRtl;
+        return ax::mojom::blink::WritingDirection::kRtl;
     }
   } else {
     switch (style->Direction()) {
       case TextDirection::kLtr:
-        return ax::mojom::blink::TextDirection::kTtb;
+        return ax::mojom::blink::WritingDirection::kTtb;
       case TextDirection::kRtl:
-        return ax::mojom::blink::TextDirection::kBtt;
+        return ax::mojom::blink::WritingDirection::kBtt;
     }
   }
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.h b/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
index b383619..d339eb3f 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
@@ -105,7 +105,7 @@
   // Properties of static elements.
   ax::mojom::blink::ListStyle GetListStyle() const final;
   String GetText() const override;
-  ax::mojom::blink::TextDirection GetTextDirection() const final;
+  ax::mojom::blink::WritingDirection GetTextDirection() const final;
   ax::mojom::blink::TextPosition GetTextPosition() const final;
   void GetTextStyleAndTextDecorationStyle(
       int32_t* text_style,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.h b/third_party/blink/renderer/modules/accessibility/ax_object.h
index 5b92ea74..d86307f 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_object.h
@@ -657,8 +657,8 @@
   virtual ax::mojom::blink::TextAlign GetTextAlign() const {
     return ax::mojom::blink::TextAlign::kNone;
   }
-  virtual ax::mojom::blink::TextDirection GetTextDirection() const {
-    return ax::mojom::blink::TextDirection::kLtr;
+  virtual ax::mojom::blink::WritingDirection GetTextDirection() const {
+    return ax::mojom::blink::WritingDirection::kLtr;
   }
   virtual ax::mojom::blink::TextPosition GetTextPosition() const {
     return ax::mojom::blink::TextPosition::kNone;
diff --git a/third_party/blink/renderer/modules/exported/web_ax_object.cc b/third_party/blink/renderer/modules/exported/web_ax_object.cc
index 2d1cb16..eddbc3b 100644
--- a/third_party/blink/renderer/modules/exported/web_ax_object.cc
+++ b/third_party/blink/renderer/modules/exported/web_ax_object.cc
@@ -965,9 +965,9 @@
   return private_->GetListStyle();
 }
 
-ax::mojom::TextDirection WebAXObject::GetTextDirection() const {
+ax::mojom::blink::WritingDirection WebAXObject::GetTextDirection() const {
   if (IsDetached())
-    return ax::mojom::TextDirection::kLtr;
+    return ax::mojom::blink::WritingDirection::kLtr;
 
   return private_->GetTextDirection();
 }
diff --git a/third_party/blink/renderer/modules/service_worker/fetch_event.cc b/third_party/blink/renderer/modules/service_worker/fetch_event.cc
index f115536..2db345f 100644
--- a/third_party/blink/renderer/modules/service_worker/fetch_event.cc
+++ b/third_party/blink/renderer/modules/service_worker/fetch_event.cc
@@ -26,6 +26,7 @@
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_load_timing.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
+#include "third_party/blink/renderer/platform/network/http_names.h"
 #include "third_party/blink/renderer/platform/network/network_utils.h"
 
 namespace blink {
@@ -141,7 +142,7 @@
   url_list[0] = preload_response_->CurrentRequestUrl();
 
   response_data->InitFromResourceResponse(
-      url_list, network::mojom::CredentialsMode::kInclude,
+      url_list, http_names::kGET, network::mojom::CredentialsMode::kInclude,
       FetchRequestData::kBasicTainting,
       preload_response_->ToResourceResponse());
 
diff --git a/third_party/blink/renderer/platform/heap/heap_stats_collector.cc b/third_party/blink/renderer/platform/heap/heap_stats_collector.cc
index ad53a97..e269afe 100644
--- a/third_party/blink/renderer/platform/heap/heap_stats_collector.cc
+++ b/third_party/blink/renderer/platform/heap/heap_stats_collector.cc
@@ -161,6 +161,11 @@
   return scope_data[kMarkProcessWorklists];
 }
 
+base::TimeDelta ThreadHeapStatsCollector::Event::flushing_v8_references_time()
+    const {
+  return scope_data[kMarkFlushV8References];
+}
+
 base::TimeDelta ThreadHeapStatsCollector::Event::atomic_marking_time() const {
   return scope_data[kAtomicPauseMarkPrologue] +
          scope_data[kAtomicPauseMarkRoots] +
@@ -238,6 +243,10 @@
   return current_.worklist_processing_time_foreground();
 }
 
+base::TimeDelta ThreadHeapStatsCollector::flushing_v8_references_time() const {
+  return current_.flushing_v8_references_time();
+}
+
 size_t ThreadHeapStatsCollector::allocated_space_bytes() const {
   return allocated_space_bytes_;
 }
diff --git a/third_party/blink/renderer/platform/heap/heap_stats_collector.h b/third_party/blink/renderer/platform/heap/heap_stats_collector.h
index ad6f20f..ef693eb 100644
--- a/third_party/blink/renderer/platform/heap/heap_stats_collector.h
+++ b/third_party/blink/renderer/platform/heap/heap_stats_collector.h
@@ -242,6 +242,9 @@
     // Time spent processing worklist in the foreground thread.
     base::TimeDelta worklist_processing_time_foreground() const;
 
+    // Time spent flushing v8 references (this is done only in the foreground)
+    base::TimeDelta flushing_v8_references_time() const;
+
     // Time spent in foreground tasks marking the heap.
     base::TimeDelta foreground_marking_time() const;
 
@@ -330,6 +333,8 @@
 
   base::TimeDelta worklist_processing_time_foreground() const;
 
+  base::TimeDelta flushing_v8_references_time() const;
+
   int64_t allocated_bytes_since_prev_gc() const;
 
   size_t allocated_space_bytes() const;
diff --git a/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.cc b/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.cc
index f17cea8d..2b5a7685 100644
--- a/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.cc
+++ b/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.cc
@@ -18,9 +18,15 @@
 
 void MarkingSchedulingOracle::UpdateIncrementalMarkingStats(
     size_t overall_marked_bytes,
-    base::TimeDelta overall_marking_time) {
+    base::TimeDelta overall_marking_time,
+    base::TimeDelta non_contributing_time) {
   incrementally_marked_bytes_ = overall_marked_bytes;
-  incremental_marking_time_so_far_ = overall_marking_time;
+  // |non_contributing_time| is time spent during |overall_marking_time| which
+  // does not contribute to |overall_marked_bytes| and is thus ignored so that
+  // it doesn't affect the marking speed.
+  DCHECK_LE(non_contributing_time, overall_marking_time);
+  incremental_marking_time_so_far_ =
+      overall_marking_time - non_contributing_time;
 }
 
 void MarkingSchedulingOracle::AddConcurrentlyMarkedBytes(size_t marked_bytes) {
diff --git a/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h b/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h
index 642304c..188c79e 100644
--- a/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h
+++ b/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h
@@ -32,7 +32,7 @@
 
   explicit MarkingSchedulingOracle();
 
-  void UpdateIncrementalMarkingStats(size_t, base::TimeDelta);
+  void UpdateIncrementalMarkingStats(size_t, base::TimeDelta, base::TimeDelta);
   void AddConcurrentlyMarkedBytes(size_t);
 
   size_t GetOverallMarkedBytes();
diff --git a/third_party/blink/renderer/platform/heap/test/marking_scheduling_oracle_test.cc b/third_party/blink/renderer/platform/heap/test/marking_scheduling_oracle_test.cc
index 5350b96..65bfc55c 100644
--- a/third_party/blink/renderer/platform/heap/test/marking_scheduling_oracle_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/marking_scheduling_oracle_test.cc
@@ -31,7 +31,8 @@
   // Add incrementally marked bytes to tell oracle this is not the first step.
   oracle.UpdateIncrementalMarkingStats(
       MarkingSchedulingOracle::kMinimumMarkedBytesInStep,
-      base::TimeDelta::FromMilliseconds(1));
+      base::TimeDelta::FromMilliseconds(1),
+      base::TimeDelta::FromMilliseconds(0));
   oracle.SetElapsedTimeForTesting(0);
   // Given marking speed set above, Minimum duration should be 1ms.
   EXPECT_EQ(1, oracle.GetNextIncrementalStepDurationForTask(kObjectSize)
@@ -42,8 +43,10 @@
   MarkingSchedulingOracle oracle;
   // Add incrementally marked bytes to tell oracle this is not the first step.
   oracle.UpdateIncrementalMarkingStats(
-      1, base::TimeDelta::FromMilliseconds(
-             MarkingSchedulingOracle::kEstimatedMarkingTimeMs));
+      1,
+      base::TimeDelta::FromMilliseconds(
+          MarkingSchedulingOracle::kEstimatedMarkingTimeMs),
+      base::TimeDelta::FromMilliseconds(0));
   oracle.SetElapsedTimeForTesting(
       MarkingSchedulingOracle::kEstimatedMarkingTimeMs);
   EXPECT_EQ(MarkingSchedulingOracle::kMaximumIncrementalMarkingStepDuration,
@@ -55,7 +58,8 @@
   // Add incrementally marked bytes to tell oracle this is not the first step.
   oracle.UpdateIncrementalMarkingStats(
       MarkingSchedulingOracle::kMinimumMarkedBytesInStep,
-      base::TimeDelta::FromMilliseconds(1));
+      base::TimeDelta::FromMilliseconds(1),
+      base::TimeDelta::FromMilliseconds(0));
   oracle.AddConcurrentlyMarkedBytes(0.6 * kObjectSize);
   oracle.SetElapsedTimeForTesting(
       0.5 * MarkingSchedulingOracle::kEstimatedMarkingTimeMs);
@@ -69,7 +73,8 @@
   MarkingSchedulingOracle oracle;
   oracle.UpdateIncrementalMarkingStats(
       0.1 * kObjectSize,
-      base::TimeDelta::FromMilliseconds(kForegoundMarkingTime));
+      base::TimeDelta::FromMilliseconds(kForegoundMarkingTime),
+      base::TimeDelta::FromMilliseconds(0));
   oracle.AddConcurrentlyMarkedBytes(0.25 * kObjectSize);
   oracle.SetElapsedTimeForTesting(
       0.5 * MarkingSchedulingOracle::kEstimatedMarkingTimeMs);
diff --git a/third_party/blink/renderer/platform/heap/thread_state.cc b/third_party/blink/renderer/platform/heap/thread_state.cc
index 45f064b..3e950f6 100644
--- a/third_party/blink/renderer/platform/heap/thread_state.cc
+++ b/third_party/blink/renderer/platform/heap/thread_state.cc
@@ -1611,7 +1611,8 @@
   // the object graph, this is fine.
   marking_scheduling_->UpdateIncrementalMarkingStats(
       visitor->marked_bytes(),
-      Heap().stats_collector()->worklist_processing_time_foreground());
+      Heap().stats_collector()->worklist_processing_time_foreground(),
+      Heap().stats_collector()->flushing_v8_references_time());
   return finished;
 }
 
diff --git a/third_party/blink/renderer/platform/widget/frame_widget.h b/third_party/blink/renderer/platform/widget/frame_widget.h
index e8fdf2b..c383722 100644
--- a/third_party/blink/renderer/platform/widget/frame_widget.h
+++ b/third_party/blink/renderer/platform/widget/frame_widget.h
@@ -123,7 +123,6 @@
       Vector<gfx::Rect>* bounds) = 0;
 
   virtual gfx::Range CompositionRange() = 0;
-  virtual WebTextInputType TextInputType() = 0;
   virtual WebTextInputInfo TextInputInfo() = 0;
   virtual ui::mojom::blink::VirtualKeyboardVisibilityRequest
   GetLastVirtualKeyboardVisibilityRequest() = 0;
diff --git a/third_party/blink/renderer/platform/widget/widget_base.cc b/third_party/blink/renderer/platform/widget/widget_base.cc
index 25bb9fd9..2485322 100644
--- a/third_party/blink/renderer/platform/widget/widget_base.cc
+++ b/third_party/blink/renderer/platform/widget/widget_base.cc
@@ -669,10 +669,7 @@
 }
 
 ui::TextInputType WidgetBase::GetTextInputType() {
-  FrameWidget* frame_widget = client_->FrameWidget();
-  if (!frame_widget)
-    return ui::TextInputType::TEXT_INPUT_TYPE_NONE;
-  return ConvertWebTextInputType(frame_widget->TextInputType());
+  return ConvertWebTextInputType(client_->GetTextInputType());
 }
 
 void WidgetBase::UpdateSelectionBounds() {
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 764df65..3304e881 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -6919,7 +6919,7 @@
 crbug.com/1104381 fast/hidpi/image-srcset-change-resource-dpr.html [ Pass Failure ]
 
 # Temporarily disable tests to allow fixing of devtools path escaping
-crbug.com/1094436 http/tests/devtools/overrides/project-added-with-existing-files-bind.js [ Pass Timeout ]
+crbug.com/1094436 http/tests/devtools/overrides/project-added-with-existing-files-bind.js [ Pass Timeout Failure ]
 crbug.com/1094436 http/tests/devtools/persistence/automapping-urlencoded-paths.js [ Pass Failure ]
 crbug.com/1094436 http/tests/devtools/sources/debugger-ui/snippet-edit-breakpoint.js [ Pass Timeout ]
 crbug.com/1094436 http/tests/devtools/sources/debugger/navigator-view.js [ Pass Failure Crash ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 363cf5a..5e65ea2 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -14734,7 +14734,7 @@
        ]
       ],
       "floats-clear-multicol-balancing-000.html": [
-       "a4f3379eca002adbe13b960198967425f7c13787",
+       "b034ceab493971d0bd37d4fc185c80677165019a",
        [
         null,
         [
@@ -14747,7 +14747,7 @@
        ]
       ],
       "floats-clear-multicol-balancing-001.html": [
-       "9c8f8148d06727ebf1c166811ef4e2c373339a32",
+       "5944343c603363864d3509489903db530b1f3f9c",
        [
         null,
         [
@@ -14760,7 +14760,7 @@
        ]
       ],
       "floats-clear-multicol-balancing-002.html": [
-       "e0343b0ce7a0f7030e2c3b1d9ae3d1056a9bebb3",
+       "99f86d1d455bb4527b390d7dbb2960198d27d098",
        [
         null,
         [
@@ -14773,7 +14773,7 @@
        ]
       ],
       "floats-clear-multicol-balancing-003.html": [
-       "8b68f3ad4ebbf98a67875f4823e8c7a348a80421",
+       "4bc32d833da7c6e1c73e728490a2b4993b4dac95",
        [
         null,
         [
@@ -73294,7 +73294,7 @@
       ]
      ],
      "multicol-basic-001.html": [
-      "e3da1a9fd7c1d46e23984cb6d704c79d899d3a7e",
+      "702cf549b1e572f4b6e17ba637603f5667d64b1c",
       [
        null,
        [
@@ -73307,7 +73307,7 @@
       ]
      ],
      "multicol-basic-002.html": [
-      "f325b85ee1b33d86b7b1a1d2dac99c26b2b3cb05",
+      "50334e96d604092f43fa2583fac0cec7062cfda6",
       [
        null,
        [
@@ -73320,7 +73320,7 @@
       ]
      ],
      "multicol-basic-003.html": [
-      "814d1e7cd82c54cbae47dbfcb13e105f40050f05",
+      "05cc1e0fe1f3259978c0eff8b55a349bab58e5ba",
       [
        null,
        [
@@ -73333,7 +73333,7 @@
       ]
      ],
      "multicol-basic-004.html": [
-      "4d8082611936d5ebd70ce2692aff8cc1a9fafd10",
+      "a6699692612985852375d0201330f31b6c64e3b3",
       [
        null,
        [
@@ -161982,7 +161982,7 @@
        []
       ],
       "floats-clear-multicol-balancing-000-ref.html": [
-       "78b7ffaf2d1a6db9064d1968a47c65b1540e57b0",
+       "e3b700c5d783c1b7e3c0a21c84d681779058132b",
        []
       ],
       "margin-collapse-024-ref.xht": [
@@ -179305,11 +179305,11 @@
       []
      ],
      "multicol-count-computed-003-ref.xht": [
-      "60074ee46c61fc59247345639866f76185243fb0",
+      "a2182c59e9bed14940f6f6802400be9be311b892",
       []
      ],
      "multicol-count-computed-004-ref.xht": [
-      "def8e5083ab45f7223a287af52953789dad1413c",
+      "f9eaa671722aedd2898799db8a72358293967898",
       []
      ],
      "multicol-dynamic-add-001-ref.html": [
@@ -179369,7 +179369,7 @@
       []
      ],
      "multicol-gap-large-001-ref.xht": [
-      "162d875e76c5c17eaf60924b85ed9011246a6ca3",
+      "3802c3653b2dcfb9bc0d15f644d5eac0a0b247e6",
       []
      ],
      "multicol-gap-large-002-ref.xht": [
@@ -179729,19 +179729,19 @@
       []
      ],
      "multicol-span-all-margin-001-ref.xht": [
-      "6605ad8efb3ea3b3e5e6396dbbf31eb572613fef",
+      "30319f3554f7aae0b567f4676a47592eb65fc707",
       []
      ],
      "multicol-span-all-margin-002-ref.xht": [
-      "1538f14025a06e2434808d424e59e8004c0da443",
+      "48b80d12fbfd54208ccbf3f55402509b16982a0a",
       []
      ],
      "multicol-span-all-margin-bottom-001-ref.xht": [
-      "2152b5663724bd65393277d21f8f1caad3128c63",
+      "b3ec5201c139a26ab5d4db65d1e00313e202d12f",
       []
      ],
      "multicol-span-all-margin-nested-001-ref.xht": [
-      "dee66329f997bdf882bbb5ee40b5a76efd11877f",
+      "44f1198df8cdd467172975ba5cf6302313fe303c",
       []
      ],
      "multicol-span-all-margin-nested-firstchild-ref.xht": [
@@ -179848,7 +179848,7 @@
        []
       ],
       "multicol-basic-ref.html": [
-       "7d88977b059defbe00f1b7dbbb37b58f607cf28b",
+       "33b4469428a20d7e49bc3cfce803ad186af7097f",
        []
       ],
       "multicol-clip-scrolled-content-001-ref.html": [
@@ -200554,19 +200554,19 @@
        []
       ],
       "request-init-stream.any-expected.txt": [
-       "43ad8c18016b2d327428b0c344ea64496105fef0",
+       "099610119e527436264172c04d3462c0aa756a3b",
        []
       ],
       "request-init-stream.any.serviceworker-expected.txt": [
-       "43ad8c18016b2d327428b0c344ea64496105fef0",
+       "099610119e527436264172c04d3462c0aa756a3b",
        []
       ],
       "request-init-stream.any.sharedworker-expected.txt": [
-       "43ad8c18016b2d327428b0c344ea64496105fef0",
+       "099610119e527436264172c04d3462c0aa756a3b",
        []
       ],
       "request-init-stream.any.worker-expected.txt": [
-       "43ad8c18016b2d327428b0c344ea64496105fef0",
+       "099610119e527436264172c04d3462c0aa756a3b",
        []
       ],
       "request-reset-attributes.https-expected.txt": [
@@ -200598,7 +200598,7 @@
        []
       ],
       "bad-chunk-encoding.py": [
-       "23c7b3f47c4d11f51c5174b86541efc5988ba155",
+       "94a77adead858b48137e3988d0c674cd945a4270",
        []
       ],
       "basic.html": [
@@ -200626,7 +200626,7 @@
        []
       ],
       "echo-content.py": [
-       "9a038f329c87e4e9dab96caa8d6fda973880d732",
+       "5e137e15d7d3b0f684b7a1a2aa0b27a719730eb4",
        []
       ],
       "empty.txt": [
@@ -200654,7 +200654,7 @@
        []
       ],
       "redirect-empty-location.py": [
-       "2baabae03b0bf368bbcd9b26a01d22ecd8e86470",
+       "1a5f7feb2a4b329473d29d45c1b245c66258d8df",
        []
       ],
       "redirect.py": [
@@ -200666,7 +200666,7 @@
        []
       ],
       "script-with-header.py": [
-       "5337cc97bdd7737e40398cb066a98a5246ba4392",
+       "9a9c70ef5cf00d7f16963004e77ff135ed92afb4",
        []
       ],
       "stash-put.py": [
@@ -200678,7 +200678,7 @@
        []
       ],
       "status.py": [
-       "5d72e10b24bfd5a36d719940388bb55d44433546",
+       "05a59d5a637edde8fb049627fdce8a3a0e836716",
        []
       ],
       "sw-intercept.js": [
@@ -200974,11 +200974,11 @@
        []
       ],
       "document-with-0x00-in-header.py": [
-       "6e8db6195910ef4c85dced8b24541ecde83c5405",
+       "223b3c4027826f2bba1394db465c93ec7cbbe001",
        []
       ],
       "script-with-0x00-in-header.py": [
-       "f4a016a369831ee5dcdb3563468ccf8dd0b0982b",
+       "39f58d8270e7671bf74e40ac84e05a7558df4f68",
        []
       ]
      }
@@ -226681,6 +226681,14 @@
      "fbc746a30b6dfa6d00fc2db747c78ec09a7beefc",
      []
     ],
+    "idlharness.https.any-expected.txt": [
+     "b19442ce9fefa877199b04b5ae0c03abc37358d1",
+     []
+    ],
+    "idlharness.https.any.worker-expected.txt": [
+     "c5b4984c269c0049c00b1b981b145ef3942a33c7",
+     []
+    ],
     "persist-permission-manual.https-expected.txt": [
      "3a7b64464fdcb74942be21a3c4b4264fd27dd9fa",
      []
@@ -242380,6 +242388,10 @@
       "46523a905a9f70183d0a5e96cff2d76ad9e6d549",
       []
      ],
+     "access-control-basic-cors-safelisted-response-headers.py": [
+      "346b6b919656b23fb911587d447756711a59231e",
+      []
+     ],
      "access-control-basic-denied.py": [
       "0d3964cb1157f75bbc59d2fa75c16aa98951a591",
       []
@@ -242404,10 +242416,6 @@
       "9b347bca4234e5dccbf5f71c3657b1a02d5c7ac6",
       []
      ],
-     "access-control-basic-whitelist-response-headers.py": [
-      "346b6b919656b23fb911587d447756711a59231e",
-      []
-     ],
      "access-control-cookie.py": [
       "8c26475c387a7de7458060f18adeab3b6429361a",
       []
@@ -242627,7 +242635,7 @@
       []
      ],
      "invalid-utf8-html.py": [
-      "c15d17151a136974fa0838cc3b3311fde2a78fa4",
+      "1c0cd84f42ffb2261d70dbad034cd99eb9ba1b90",
       []
      ],
      "last-modified.py": [
@@ -242689,7 +242697,7 @@
       []
      ],
      "shift-jis-html.py": [
-      "47c67d8ae39e96bacd97d7cb14c59151060e2683",
+      "b3326c1ba7b3b2398fc1933ae4a49ad05a005b84",
       []
      ],
      "status.py": [
@@ -242725,7 +242733,7 @@
       []
      ],
      "win-1252-xml.py": [
-      "d88086e936ea17f75f30c18f4e9bd424ba609fff",
+      "50e9f04fb8dde0f20b07c5b0777caa005480be3a",
       []
      ],
      "workerxhr-origin-referrer.js": [
@@ -321333,7 +321341,7 @@
          ]
         ],
         "canvas-createImageBitmap-e_srgb.html": [
-         "9cad95a87ba552bba2b055e97f048b3589f993a5",
+         "829e120df45fd43b7f34616ca1385d8dbee9ccf5",
          [
           null,
           {}
@@ -412148,7 +412156,7 @@
      ]
     ],
     "access-control-basic-cors-safelisted-response-headers.htm": [
-     "a5c470b74f51d6c577d335159427d3c804bce5ba",
+     "be9a10ef0163a928a5ad6144d9d979b270e2cf24",
      [
       null,
       {}
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-000-ref.html b/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-000-ref.html
index 78b7ffaf..e3b700c 100644
--- a/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-000-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-000-ref.html
@@ -20,7 +20,7 @@
   height: 250px;
 }
 .clear {
-  border-bottom: solid orange;
+  border-bottom: 5px solid orange;
   background: red;
 }
 </style>
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-000.html b/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-000.html
index a4f3379e..b034cea 100644
--- a/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-000.html
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-000.html
@@ -32,7 +32,7 @@
 }
 
 .clear {
-  border-bottom: solid orange;
+  border-bottom: 5px solid orange;
 }
 </style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-001.html b/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-001.html
index 9c8f814..5944343c 100644
--- a/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-001.html
@@ -31,7 +31,7 @@
 }
 
 .clear {
-  border-bottom: solid orange;
+  border-bottom: 5px solid orange;
   background: red;
 }
 </style>
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-002.html b/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-002.html
index e0343b0..99f86d1 100644
--- a/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-002.html
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-002.html
@@ -33,7 +33,7 @@
 
 .clear {
   clear: left;
-  border-bottom: solid orange;
+  border-bottom: 5px solid orange;
   background: red;
 }
 </style>
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-003.html b/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-003.html
index 8b68f3a..4bc32d83 100644
--- a/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-003.html
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/floats-clear-multicol-balancing-003.html
@@ -42,7 +42,7 @@
   background: red;
 }
 .bar {
-  border-bottom: orange solid;
+  border-bottom: 5px orange solid;
 }
 </style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-001.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-001.html
index e3da1a9f..702cf54 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-001.html
@@ -14,7 +14,7 @@
 	<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 	<style type="text/css">
 		.multicol-wrapper>*{
-			font-family: Ahem;
+			font: 20px/1 Ahem;
 		}
 
 		div.multicol-wrapper{
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-002.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-002.html
index f325b85..50334e9 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-002.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-002.html
@@ -14,7 +14,7 @@
 	<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 	<style type="text/css">
 		.multicol-wrapper>*{
-			font-family: Ahem;
+			font: 20px/1 Ahem;
 		}
 
 		div.multicol-wrapper{
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-003.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-003.html
index 814d1e7..05cc1e0f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-003.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-003.html
@@ -14,7 +14,7 @@
 	<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 	<style type="text/css">
 		.multicol-wrapper>*{
-			font-family: Ahem;
+			font: 20px/1 Ahem;
 		}
 
 		div.multicol-wrapper{
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-004.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-004.html
index 4d808261..a669969 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-004.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-basic-004.html
@@ -14,7 +14,7 @@
 	<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 	<style type="text/css">
 		.multicol-wrapper>*{
-			font-family: Ahem;
+			font: 20px/1 Ahem;
 		}
 
 		div.multicol-wrapper{
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-count-computed-003-ref.xht b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-count-computed-003-ref.xht
index 60074ee4..a2182c5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-count-computed-003-ref.xht
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-count-computed-003-ref.xht
@@ -4,9 +4,11 @@
   <title>CSS Reftest Reference</title>
   <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
   <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-07-29 -->
-  <meta name="flags" content="image" />
+  <meta name="flags" content="image ahem" />
+  <link rel="stylesheet" href="/fonts/ahem.css" />
 
   <style type="text/css"><![CDATA[
+  body {font: 1.25em/1 Ahem;}
   img {vertical-align: top;}
   ]]></style>
  </head>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-count-computed-004-ref.xht b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-count-computed-004-ref.xht
index def8e508..f9eaa67 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-count-computed-004-ref.xht
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-count-computed-004-ref.xht
@@ -4,9 +4,11 @@
   <title>CSS Reftest Reference</title>
   <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
   <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-07-29 -->
-  <meta name="flags" content="image" />
+  <meta name="flags" content="image ahem" />
+  <link rel="stylesheet" href="/fonts/ahem.css" />
 
   <style type="text/css"><![CDATA[
+  body {font: 1.25em/1 Ahem;}
   img {vertical-align: top;}
   ]]></style>
  </head>
@@ -22,4 +24,4 @@
   <div><img src="support/swatch-gray.png" width="280" height="20" alt="Image download support must be enabled" /></div>
 
  </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-gap-large-001-ref.xht b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-gap-large-001-ref.xht
index 162d875..3802c365 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-gap-large-001-ref.xht
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-gap-large-001-ref.xht
@@ -4,8 +4,10 @@
   <title>CSS Reftest Reference</title>
   <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
   <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-08-06 -->
-  <meta name="flags" content="image" />
+  <meta name="flags" content="image ahem" />
+  <link rel="stylesheet" href="/fonts/ahem.css" />
   <style type="text/css"><![CDATA[
+  body {font: 1.25em/1 Ahem;}
   img {vertical-align: top;}
   ]]></style>
  </head>
@@ -18,4 +20,4 @@
   <div><img src="support/swatch-gray.png" width="260" height="20" alt="Image download support must be enabled" /></div>
 
  </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-001-ref.xht b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-001-ref.xht
index 6605ad8..30319f3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-001-ref.xht
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-001-ref.xht
@@ -4,11 +4,13 @@
   <title>CSS Reftest Reference</title>
   <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
   <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-08-18 -->
-  <meta name="flags" content="image" />
+  <meta name="flags" content="image ahem" />
+  <link rel="stylesheet" href="/fonts/ahem.css" />
   <style type="text/css"><![CDATA[
   div
   {
-  border: gray solid 1.25em;
+  font: 1.25em/1 Ahem;
+  border: gray solid 1em;
   width: 160px;
   }
 
@@ -20,4 +22,4 @@
   <div><img src="support/swatch-blue.png" width="80" height="40" alt="Image download support must be enabled" /><img src="support/swatch-pink.png" width="80" height="40" alt="Image download support must be enabled" /> <img src="support/swatch-yellow.png" width="160" height="20" alt="Image download support must be enabled" /> <img src="support/black20x20.png" width="160" height="20" alt="Image download support must be enabled" /> <img src="support/swatch-yellow.png" width="160" height="20" alt="Image download support must be enabled" /> <img src="support/black20x20.png" width="160" height="20" alt="Image download support must be enabled" /> <img src="support/swatch-yellow.png" width="160" height="20" alt="Image download support must be enabled" /> <img src="support/swatch-navy.png" width="160" height="40" alt="Image download support must be enabled" /></div>
 
  </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-002-ref.xht b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-002-ref.xht
index 1538f14..48b80d1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-002-ref.xht
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-002-ref.xht
@@ -4,8 +4,11 @@
   <title>CSS Reftest Reference</title>
   <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
   <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-08-19 -->
-  <meta name="flags" content="image" />
+  <meta name="flags" content="image ahem" />
+  <link rel="stylesheet" href="/fonts/ahem.css" />
   <style type="text/css"><![CDATA[
+  body {font: 1.25em/1 Ahem;}
+
   div {width: 240px;}
 
   img {vertical-align: top;}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-bottom-001-ref.xht b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-bottom-001-ref.xht
index 2152b56..b3ec520 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-bottom-001-ref.xht
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-bottom-001-ref.xht
@@ -4,11 +4,13 @@
   <title>CSS Reftest Reference</title>
   <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
   <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-08-19 -->
-  <meta name="flags" content="image" />
+  <meta name="flags" content="image ahem" />
+  <link rel="stylesheet" href="/fonts/ahem.css" />
   <style type="text/css"><![CDATA[
   div
   {
-  border: gray solid 1.25em;
+  font: 1.25em/1 Ahem;
+  border: gray solid 1em;
   width: 160px;
   }
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-nested-001-ref.xht b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-nested-001-ref.xht
index dee6632..44f1198 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-nested-001-ref.xht
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-margin-nested-001-ref.xht
@@ -4,11 +4,13 @@
   <title>CSS Reftest Reference</title>
   <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
   <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-08-19 -->
-  <meta name="flags" content="image" />
+  <meta name="flags" content="image ahem" />
+  <link rel="stylesheet" href="/fonts/ahem.css" />
   <style type="text/css"><![CDATA[
   div
   {
-  border: gray solid 1.25em;
+  font: 1.25em/1 Ahem;
+  border: gray solid 1em;
   width: 160px;
   }
 
@@ -28,4 +30,4 @@
   </div>
 
  </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/reference/multicol-basic-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/reference/multicol-basic-ref.html
index 7d88977b0..33b4469 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/reference/multicol-basic-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/reference/multicol-basic-ref.html
@@ -10,7 +10,7 @@
 	<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 	<style type="text/css">
 		.multicol-wrapper>*{
-			font-family: Ahem;
+			font: 20px/1 Ahem;
 		}
 
 		div.multicol-wrapper{
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/resources/bad-chunk-encoding.py b/third_party/blink/web_tests/external/wpt/fetch/api/resources/bad-chunk-encoding.py
index 23c7b3f..94a77ade 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/resources/bad-chunk-encoding.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/resources/bad-chunk-encoding.py
@@ -1,13 +1,13 @@
 import time
 
 def main(request, response):
-    delay = float(request.GET.first("ms", 1000)) / 1E3
-    count = int(request.GET.first("count", 50))
+    delay = float(request.GET.first(b"ms", 1000)) / 1E3
+    count = int(request.GET.first(b"count", 50))
     time.sleep(delay)
-    response.headers.set("Transfer-Encoding", "chunked")
+    response.headers.set(b"Transfer-Encoding", b"chunked")
     response.write_status_headers()
     time.sleep(delay)
-    for i in xrange(count):
-        response.writer.write_content("a\r\nTEST_CHUNK\r\n")
+    for i in range(count):
+        response.writer.write_content(b"a\r\nTEST_CHUNK\r\n")
         time.sleep(delay)
-    response.writer.write_content("garbage")
+    response.writer.write_content(b"garbage")
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/resources/echo-content.py b/third_party/blink/web_tests/external/wpt/fetch/api/resources/echo-content.py
index 9a038f3..5e137e1 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/resources/echo-content.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/resources/echo-content.py
@@ -1,10 +1,12 @@
+from wptserve.utils import isomorphic_encode
+
 def main(request, response):
 
-    headers = [("X-Request-Method", request.method),
-               ("X-Request-Content-Length", request.headers.get("Content-Length", "NO")),
-               ("X-Request-Content-Type", request.headers.get("Content-Type", "NO")),
+    headers = [(b"X-Request-Method", isomorphic_encode(request.method)),
+               (b"X-Request-Content-Length", request.headers.get(b"Content-Length", b"NO")),
+               (b"X-Request-Content-Type", request.headers.get(b"Content-Type", b"NO")),
                # Avoid any kind of content sniffing on the response.
-               ("Content-Type", "text/plain")]
+               (b"Content-Type", b"text/plain")]
     content = request.body
 
     return headers, content
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/resources/redirect-empty-location.py b/third_party/blink/web_tests/external/wpt/fetch/api/resources/redirect-empty-location.py
index 2baabae..1a5f7fe 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/resources/redirect-empty-location.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/resources/redirect-empty-location.py
@@ -1,3 +1,3 @@
 def main(request, response):
-    headers = [("Location", "")]
-    return 302, headers, ""
+    headers = [(b"Location", b"")]
+    return 302, headers, b""
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/resources/script-with-header.py b/third_party/blink/web_tests/external/wpt/fetch/api/resources/script-with-header.py
index 5337cc9..9a9c70ef 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/resources/script-with-header.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/resources/script-with-header.py
@@ -1,7 +1,7 @@
 def main(request, response):
-    headers = [("Content-type", request.GET.first("mime"))]
-    if "content" in request.GET and request.GET.first("content") == "empty":
-        content = ''
+    headers = [(b"Content-type", request.GET.first(b"mime"))]
+    if b"content" in request.GET and request.GET.first(b"content") == b"empty":
+        content = b''
     else:
-        content = "console.log('Script loaded')"
+        content = b"console.log('Script loaded')"
     return 200, headers, content
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/resources/status.py b/third_party/blink/web_tests/external/wpt/fetch/api/resources/status.py
index 5d72e10..05a59d5 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/resources/status.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/resources/status.py
@@ -1,9 +1,11 @@
+from wptserve.utils import isomorphic_encode
+
 def main(request, response):
-    code = int(request.GET.first("code", 200))
-    text = request.GET.first("text", "OMG")
-    content = request.GET.first("content", "")
-    type = request.GET.first("type", "")
+    code = int(request.GET.first(b"code", 200))
+    text = request.GET.first(b"text", b"OMG")
+    content = request.GET.first(b"content", b"")
+    type = request.GET.first(b"type", b"")
     status = (code, text)
-    headers = [("Content-Type", type),
-               ("X-Request-Method", request.method)]
+    headers = [(b"Content-Type", type),
+               (b"X-Request-Method", isomorphic_encode(request.method))]
     return status, headers, content
diff --git a/third_party/blink/web_tests/external/wpt/fetch/h1-parsing/resources/document-with-0x00-in-header.py b/third_party/blink/web_tests/external/wpt/fetch/h1-parsing/resources/document-with-0x00-in-header.py
index 6e8db61..223b3c4 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/h1-parsing/resources/document-with-0x00-in-header.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/h1-parsing/resources/document-with-0x00-in-header.py
@@ -1,4 +1,4 @@
 def main(request, response):
-    response.headers.set("Content-Type", "text/html")
-    response.headers.set("Custom", "\0")
-    return "<!doctype html><b>This is a document.</b>"
+    response.headers.set(b"Content-Type", b"text/html")
+    response.headers.set(b"Custom", b"\0")
+    return b"<!doctype html><b>This is a document.</b>"
diff --git a/third_party/blink/web_tests/external/wpt/fetch/h1-parsing/resources/script-with-0x00-in-header.py b/third_party/blink/web_tests/external/wpt/fetch/h1-parsing/resources/script-with-0x00-in-header.py
index f4a016a3..39f58d8 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/h1-parsing/resources/script-with-0x00-in-header.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/h1-parsing/resources/script-with-0x00-in-header.py
@@ -1,4 +1,4 @@
 def main(request, response):
-    response.headers.set("Content-Type", "text/javascript")
-    response.headers.set("Custom", "\0")
-    return "var thisIsJavaScript = 0"
+    response.headers.set(b"Content-Type", b"text/javascript")
+    response.headers.set(b"Custom", b"\0")
+    return b"var thisIsJavaScript = 0"
diff --git a/third_party/blink/web_tests/external/wpt/native-io/rename_async_failure_handling.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/native-io/rename_async_failure_handling.tentative.https.any.js
index 5e0f964..64ea24f 100644
--- a/third_party/blink/web_tests/external/wpt/native-io/rename_async_failure_handling.tentative.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/native-io/rename_async_failure_handling.tentative.https.any.js
@@ -93,8 +93,8 @@
   closed_file.close();
   const opened_file = await nativeIO.open('opened_file');
   testCase.add_cleanup(async () => {
-    closed_file.close();
-    opened_file.close();
+    await closed_file.close();
+    await opened_file.close();
     await nativeIO.delete('closed_file');
     await nativeIO.delete('opened_file');
   });
diff --git a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getPointAtLength-02.svg b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getPointAtLength-02.svg
index 4cf93da..9420503d 100644
--- a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getPointAtLength-02.svg
+++ b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getPointAtLength-02.svg
@@ -1,13 +1,12 @@
 <svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml">
   <title>SVGGeometryElement.prototype.getPointAtLength() query with 'pathLength'</title>
   <h:link rel="help" href="https://svgwg.org/svg2-draft/types.html#__svg__SVGGeometryElement__getPointAtLength"/>
+  <path id='pathElement' d='M0,0L100,0L100,100' pathLength="1000"/>
   <h:script src="/resources/testharness.js"/>
   <h:script src="/resources/testharnessreport.js"/>
   <script>
 test(function() {
-    let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
-    path.setAttribute('d', 'M0,0L100,0L100,100');
-    path.setAttribute('pathLength', '1000');
+    let path = document.getElementById('pathElement');
 
     var point = path.getPointAtLength(50);
     assert_approx_equals(point.x, 50, 1e-5);
diff --git a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getPointAtLength-03.svg b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getPointAtLength-03.svg
new file mode 100644
index 0000000..61737efb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getPointAtLength-03.svg
@@ -0,0 +1,30 @@
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     xmlns:html="http://www.w3.org/1999/xhtml">
+  <title>When SVGGeometryElement.getPointAtLength is called with an element that is not in the document, throw exception</title>
+  <html:link rel="help" href="https://svgwg.org/svg2-draft/types.html#__svg__SVGGeometryElement__getPointAtLength"/>
+  <html:script src="/resources/testharness.js"/>
+  <html:script src="/resources/testharnessreport.js"/>
+  <script><![CDATA[
+  test(function() {
+    var pathElement = document.createElementNS("http://www.w3.org/2000/svg", "path");
+    pathElement.setAttribute("d", 'M0,20 L400,20 L640,20');
+    assert_throws_dom("InvalidStateError", function() { pathElement.getPointAtLength(700) });
+  }, document.title + " with SVGPathElement");
+
+  test(function() {
+    var rectElement = document.createElementNS("http://www.w3.org/2000/svg", "rect");
+    rectElement.setAttribute("rx", 0);
+    rectElement.setAttribute("ry", 0);
+    rectElement.setAttribute("width", 200);
+    rectElement.setAttribute("height", 300);
+    assert_throws_dom("InvalidStateError", function() { rectElement.getPointAtLength(300); });
+  }, document.title + " with SVGRectElement");
+
+  test(function() {
+    var circleElement = document.createElementNS("http://www.w3.org/2000/svg", "circle");
+    circleElement.setAttribute("r", 10);
+    assert_throws_dom("InvalidStateError", function() { circleElement.getPointAtLength(100); });
+  }, document.title + " with SVGCircleElement");
+  ]]></script>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getPointAtLength-04.svg b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getPointAtLength-04.svg
new file mode 100644
index 0000000..f0a1363
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getPointAtLength-04.svg
@@ -0,0 +1,79 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml">
+  <title>SVGGeometryElement.getPointAtLength: 'display' and a valid path</title>
+  <h:link rel="help" href="https://svgwg.org/svg2-draft/types.html#__svg__SVGGeometryElement__getPointAtLength"/>
+  <h:script src="/resources/testharness.js"/>
+  <h:script src="/resources/testharnessreport.js"/>
+  <path id='pathElement1' d='M0,0L100,0L100,100' description='path with display: defualt'/>
+  <path id='pathElement2' style='display:none' d='M0,0L100,0L100,100' description='path with display: none'/>
+  <rect id='rectElement1' x='0' y='0' width='50' height='50' description='rect with display: default'/>
+  <rect id='rectElement2' style='display:none' x='0' y='0' width='50' height='50' description='rect with display: none'/>
+  <circle id='circleElement1' cx='0' cy='0' r='50' description='circle with display: defualt'/>
+  <circle id='circleElement2' style='display:none' cx='0' cy='0' r='50' description='circle with display: none'/>
+  <polygon id='polygonElement1' points="0,0 50,0 50,50 0,50" description='polygon with display: default'/>
+  <polygon id='polygonElement2' style='display:none' points="0,0 50,0 50,50 0,50" description='polygon with display: none'/>
+  <polyline id='polylineElement1' points="0,0 50,0 50,50 0,50" description='polyline with display: default'/>
+  <polyline id='polylineElement2' style='display:none' points="0,0 50,0 50,50 0,50" description='polyline with display: none'/>
+  <ellipse id='ellipseElement1' cx='0' cy='0' rx='50' ry='50' description='ellipse with display: default'/>
+  <ellipse id='ellipseElement2' style='display:none' cx='0' cy='0' rx='50' ry='50' description='ellipse with display: none'/>
+  <script>
+['pathElement1', 'pathElement2'].forEach(elementId => {
+  test(function() {
+    let element = document.getElementById(elementId);
+    var point = element.getPointAtLength(50);
+    assert_approx_equals(point.x, 50, 1e-5);
+    assert_approx_equals(point.y, 0, 1e-5);
+  }, document.title + ', ' +
+     document.getElementById(elementId).getAttribute('description'));
+});
+
+['rectElement1', 'rectElement2'].forEach(elementId => {
+  test(function() {
+    let element = document.getElementById(elementId);
+    var point = element.getPointAtLength(50);
+    assert_approx_equals(point.x, 50, 1e-5);
+    assert_approx_equals(point.y, 0, 1e-5);
+  }, document.title + ', ' +
+     document.getElementById(elementId).getAttribute('description'));
+});
+
+['circleElement1', 'circleElement2'].forEach(elementId => {
+  test(function() {
+    let element = document.getElementById(elementId);
+    var point = element.getPointAtLength(0);
+    assert_approx_equals(point.x, 50, 1e-5);
+    assert_approx_equals(point.y, 0, 1e-5);
+  }, document.title + ', ' +
+     document.getElementById(elementId).getAttribute('description'));
+});
+
+['polygonElement1', 'polygonElement2'].forEach(elementId => {
+  test(function() {
+    let element = document.getElementById(elementId);
+    var point = element.getPointAtLength(50);
+    assert_approx_equals(point.x, 50, 1e-5);
+    assert_approx_equals(point.y, 0, 1e-5);
+  }, document.title + ', ' +
+     document.getElementById(elementId).getAttribute('description'));
+});
+
+['polylineElement1', 'polylineElement2'].forEach(elementId => {
+  test(function() {
+    let element = document.getElementById(elementId);
+    var point = element.getPointAtLength(50);
+    assert_approx_equals(point.x, 50, 1e-5);
+    assert_approx_equals(point.y, 0, 1e-5);
+  }, document.title + ', ' +
+     document.getElementById(elementId).getAttribute('description'));
+});
+
+['ellipseElement1', 'ellipseElement2'].forEach(elementId => {
+  test(function() {
+    let element = document.getElementById(elementId);
+    var point = element.getPointAtLength(0);
+    assert_approx_equals(point.x, 50, 1e-5);
+    assert_approx_equals(point.y, 0, 1e-5);
+  }, document.title + ', ' +
+     document.getElementById(elementId).getAttribute('description'));
+});
+  </script>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getPointAtLength-05.svg b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getPointAtLength-05.svg
new file mode 100644
index 0000000..50a7137
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getPointAtLength-05.svg
@@ -0,0 +1,67 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml">
+  <title>SVGGeometryElement.getPointAtLength: 'display' and empty path</title>
+  <h:link rel="help" href="https://svgwg.org/svg2-draft/types.html#__svg__SVGGeometryElement__getPointAtLength"/>
+  <h:script src="/resources/testharness.js"/>
+  <h:script src="/resources/testharnessreport.js"/>
+  <path id='pathElement1' description='path with display: defualt and an empty path'/>
+  <path id='pathElement2' style='display:none' description='path with display: none and an empty path'/>
+  <rect id='rectElement1' description='rect with display: defualt and an empty path'/>
+  <rect id='rectElement2' style='display:none' description='rect with display: none and an empty path'/>
+  <circle id='circleElement1' description='circle with display: default and an empty path'/>
+  <circle id='circleElement2' style='display:none' description='circle with display: none and an empty path'/>
+  <polygon id='polygonElement1' description='polygon with display: defualt and an empty path'/>
+  <polygon id='polygonElement2' style='display:none' description='polygon with display: none and an empty path'/>
+  <polyline id='polylineElement1' description='polyline with display: default and an empty path'/>
+  <polyline id='polylineElement2' style='display:none' description='polyline with display: none and an empty path'/>
+  <ellipse id='ellipseElement1' description='ellipse with display: default and an empty path'/>
+  <ellipse id='ellipseElement2' style='display:none' description='ellipse with display: none and an empty path'/>
+  <script>
+['pathElement1', 'pathElement2'].forEach(elementId => {
+  test(function() {
+    let element = document.getElementById(elementId);
+    assert_throws_dom("InvalidStateError", function() { element.getPointAtLength(300); });
+  }, document.title + ', ' +
+     document.getElementById(elementId).getAttribute('description'));
+});
+
+['rectElement1', 'rectElement2'].forEach(elementId => {
+  test(function() {
+    let element = document.getElementById(elementId);
+    assert_throws_dom("InvalidStateError", function() { element.getPointAtLength(300); });
+  }, document.title + ', ' +
+     document.getElementById(elementId).getAttribute('description'));
+});
+
+['circleElement1', 'circleElement2'].forEach(elementId => {
+  test(function() {
+    let element = document.getElementById(elementId);
+    assert_throws_dom("InvalidStateError", function() { element.getPointAtLength(300); });
+  }, document.title + ', ' +
+     document.getElementById(elementId).getAttribute('description'));
+});
+
+['polygonElement1', 'polygonElement2'].forEach(elementId => {
+  test(function() {
+    let element = document.getElementById(elementId);
+    assert_throws_dom("InvalidStateError", function() { element.getPointAtLength(300); });
+  }, document.title + ', ' +
+     document.getElementById(elementId).getAttribute('description'));
+});
+
+['polylineElement1', 'polylineElement2'].forEach(elementId => {
+  test(function() {
+    let element = document.getElementById(elementId);
+    assert_throws_dom("InvalidStateError", function() { element.getPointAtLength(300); });
+  }, document.title + ', ' +
+     document.getElementById(elementId).getAttribute('description'));
+});
+
+['ellipseElement1', 'ellipseElement2'].forEach(elementId => {
+  test(function() {
+    let element = document.getElementById(elementId);
+    assert_throws_dom("InvalidStateError", function() { element.getPointAtLength(300); });
+  }, document.title + ', ' +
+     document.getElementById(elementId).getAttribute('description'));
+});
+  </script>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/xhr/access-control-basic-cors-safelisted-response-headers.htm b/third_party/blink/web_tests/external/wpt/xhr/access-control-basic-cors-safelisted-response-headers.htm
index a5c470b..be9a10e 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/access-control-basic-cors-safelisted-response-headers.htm
+++ b/third_party/blink/web_tests/external/wpt/xhr/access-control-basic-cors-safelisted-response-headers.htm
@@ -12,7 +12,7 @@
       const xhr = new XMLHttpRequest;
 
       xhr.open("GET", get_host_info().HTTP_REMOTE_ORIGIN +
-          "/xhr/resources/access-control-basic-whitelist-response-headers.py", false);
+          "/xhr/resources/access-control-basic-cors-safelisted-response-headers.py", false);
       xhr.send();
 
       assert_not_equals(xhr.getResponseHeader("cache-control"), null);
diff --git a/third_party/blink/web_tests/external/wpt/xhr/resources/access-control-basic-whitelist-response-headers.py b/third_party/blink/web_tests/external/wpt/xhr/resources/access-control-basic-cors-safelisted-response-headers.py
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/xhr/resources/access-control-basic-whitelist-response-headers.py
rename to third_party/blink/web_tests/external/wpt/xhr/resources/access-control-basic-cors-safelisted-response-headers.py
diff --git a/third_party/blink/web_tests/external/wpt/xhr/resources/invalid-utf8-html.py b/third_party/blink/web_tests/external/wpt/xhr/resources/invalid-utf8-html.py
index c15d171..1c0cd84 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/resources/invalid-utf8-html.py
+++ b/third_party/blink/web_tests/external/wpt/xhr/resources/invalid-utf8-html.py
@@ -1,5 +1,7 @@
+from six import int2byte
+
 def main(request, response):
     headers = [(b"Content-type", b"text/html;charset=utf-8")]
-    content = chr(0xff)
+    content = int2byte(0xff)
 
     return headers, content
diff --git a/third_party/blink/web_tests/external/wpt/xhr/resources/shift-jis-html.py b/third_party/blink/web_tests/external/wpt/xhr/resources/shift-jis-html.py
index 47c67d8..b3326c1 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/resources/shift-jis-html.py
+++ b/third_party/blink/web_tests/external/wpt/xhr/resources/shift-jis-html.py
@@ -1,6 +1,8 @@
+from six import int2byte
+
 def main(request, response):
     headers = [(b"Content-type", b"text/html;charset=shift-jis")]
     # Shift-JIS bytes for katakana TE SU TO ('test')
-    content = chr(0x83) + chr(0x65) + chr(0x83) + chr(0x58) + chr(0x83) + chr(0x67)
+    content = int2byte(0x83) + int2byte(0x65) + int2byte(0x83) + int2byte(0x58) + int2byte(0x83) + int2byte(0x67)
 
     return headers, content
diff --git a/third_party/blink/web_tests/external/wpt/xhr/resources/win-1252-xml.py b/third_party/blink/web_tests/external/wpt/xhr/resources/win-1252-xml.py
index d88086e..50e9f04f 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/resources/win-1252-xml.py
+++ b/third_party/blink/web_tests/external/wpt/xhr/resources/win-1252-xml.py
@@ -1,5 +1,7 @@
+from six import int2byte
+
 def main(request, response):
     headers = [(b"Content-type", b"application/xml;charset=windows-1252")]
-    content = '<' + chr(0xff) + '/>'
+    content = b'<' + int2byte(0xff) + b'/>'
 
     return headers, content
diff --git a/third_party/blink/web_tests/http/tests/cachestorage/padding.html b/third_party/blink/web_tests/http/tests/cachestorage/padding.html
index 49c9a08..1e50d195 100644
--- a/third_party/blink/web_tests/http/tests/cachestorage/padding.html
+++ b/third_party/blink/web_tests/http/tests/cachestorage/padding.html
@@ -6,9 +6,20 @@
 <script>
 'use strict';
 
-async function usage_for_credentials(cache, url, mode) {
-  const r = await fetch(url, { mode: 'no-cors', credentials: mode });
+async function usage(cache, url, init, clone) {
+  const i = { mode: 'no-cors' };
+  let r = await fetch(url, {
+    mode: 'no-cors',
+    credentials: init.credentials,
+    method: init.method,
+  });
   assert_equals('opaque', r.type);
+  if (clone)
+    r = r.clone();
+  // Note, this stores the response under a Request key that has different
+  // attributes than what we fetched above.  This is purposeful to ensure
+  // that we are varying on how the Response was loaded and not on the Request
+  // key.
   await cache.put(url, r);
   return (await navigator.storage.estimate()).usage;
 }
@@ -18,12 +29,12 @@
   const url = 'http://localhost:8000/cachestorage/resources/simple.txt';
 
   // Get the reported disk usage for an opaque response without credentials.
-  const usage1 = await usage_for_credentials(cache, url, 'omit');
-  const usage2 = await usage_for_credentials(cache, url, 'same-origin');
+  const usage1 = await usage(cache, url, { credentials: 'omit' });
+  const usage2 = await usage(cache, url, { credentials: 'same-origin' });
 
   // Get the reported disk usage for an opaque response with the same URL,
   // but also with credentials enabled.
-  const usage3 = await usage_for_credentials(cache, url, 'include');
+  const usage3 = await usage(cache, url, { credentials: 'include' });
 
   assert_equals(usage1, usage2,
                 "Credentials mode 'omit' and 'same-origin' should have the " +
@@ -33,4 +44,54 @@
                     "padding size.");
 }, 'Cache padding varies based on if Response was loaded with credentials.');
 
+promise_test(async t => {
+  const cache = await caches.open('padding');
+  const url = 'http://localhost:8000/cachestorage/resources/simple.txt';
+
+  const usage1 = await usage(cache, url, { method: 'GET' });
+  const usage1b = await usage(cache, url, { method: 'GET' });
+  assert_equals(usage1, usage1b,
+                "Usage should be same if the request does not vary.");
+
+  const usage2 = await usage(cache, url, { method: 'HEAD' });
+  const usage2b = await usage(cache, url, { method: 'HEAD' });
+  assert_equals(usage2, usage2b,
+                "Usage should be same if the request does not vary.");
+
+  const usage3 = await usage(cache, url, { method: 'POST' });
+  const usage3b = await usage(cache, url, { method: 'POST' });
+  assert_equals(usage3, usage3b,
+                "Usage should be same if the request does not vary.");
+
+  // It should only be possible to create opaque responses with CORS
+  // safelisted methods.
+  await promise_rejects_js(t, TypeError, usage(cache, url, { method: 'OPTIONS' }));
+  await promise_rejects_js(t, TypeError, usage(cache, url, { method: 'CONNECT' }));
+  await promise_rejects_js(t, TypeError, usage(cache, url, { method: 'TRACE' }));
+  await promise_rejects_js(t, TypeError, usage(cache, url, { method: 'TRACK' }));
+  await promise_rejects_js(t, TypeError, usage(cache, url, { method: 'PUT' }));
+  await promise_rejects_js(t, TypeError, usage(cache, url, { method: 'PATCH' }));
+  await promise_rejects_js(t, TypeError, usage(cache, url, { method: 'FOO' }));
+
+  assert_not_equals(usage1, usage2,
+                    "Methods 'GET' and 'HEAD' should result in different " +
+                    "padding sizes.");
+  assert_not_equals(usage1, usage3,
+                    "Methods 'GET' and 'POST' should result in different " +
+                    "padding sizes.");
+  assert_not_equals(usage2, usage3,
+                    "Methods 'HEAD' and 'POST' should result in different " +
+                    "padding sizes.");
+}, 'Cache padding varies based on Response original request method.');
+
+promise_test(async t => {
+  const cache = await caches.open('padding');
+  const url = 'http://localhost:8000/cachestorage/resources/simple.txt';
+  const init = { method: 'GET', credentials: 'include' };
+
+  const usage1 = await usage(cache, url, init, /* clone=*/ false);
+  const usage2 = await usage(cache, url, init, /* clone=*/ true);
+  assert_equals(usage1, usage2, "Usage should not vary based on cloning.");
+}, 'Cache padding does not change when cloned.');
+
 </script>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/content-security-policy-issue-with-src-location.html b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/content-security-policy-issue-with-src-location.html
index 39c0dff..735c7b3e 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/content-security-policy-issue-with-src-location.html
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/content-security-policy-issue-with-src-location.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<meta http-equiv="Content-Security-Policy" content="style-src 'https://thirdparty.test/network/resources/';">
+<meta http-equiv="Content-Security-Policy" content="style-src https://thirdparty.test/network/resources/;">
 
 <link rel="stylesheet" type="text/css" href="style.css">
 
diff --git a/third_party/blink/web_tests/media/controls-strict.html b/third_party/blink/web_tests/media/controls-strict.html
index 9db9a26..a553a62 100644
--- a/third_party/blink/web_tests/media/controls-strict.html
+++ b/third_party/blink/web_tests/media/controls-strict.html
@@ -1,26 +1,16 @@
 <!DOCTYPE HTML>
 <html>
     <head>
-        <script src="../resources/run-after-layout-and-paint.js"></script>
+        <script src="media-file.js"></script>
+        <script src="video-paint-test.js"></script>
         <script src="media-controls.js"></script>
     </head>
-    <body>
+    <body onload="setSrcByTagName('video', 'content/test.ogv'); init()">
         <p>Drawing the controls in strict mode.</p>
-        <video controls src='content/test.ogv'></video>
+        <video controls></video>
     </body>
     <script>
       const video = document.querySelector('video');
       enableTestMode(video);
-
-      if (window.testRunner) {
-        testRunner.waitUntilDone();
-
-        video.addEventListener('loadedmetadata', () => {
-          runAfterLayoutAndPaint(() => {
-            if (window.testRunner)
-              testRunner.notifyDone();
-          });
-        }, { once: true });
-      }
     </script>
 </html>
diff --git a/third_party/blink/web_tests/svg/dom/SVGGeometryElement-getPointAtLength-detached.html b/third_party/blink/web_tests/svg/dom/SVGGeometryElement-getPointAtLength-detached.html
deleted file mode 100644
index 85fbe3a5..0000000
--- a/third_party/blink/web_tests/svg/dom/SVGGeometryElement-getPointAtLength-detached.html
+++ /dev/null
@@ -1,52 +0,0 @@
-<!DOCTYPE html>
-<title>SVGGeometryElement.getPointAtLength method (element detached)</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script>
-test(function() {
-  var pathElement = document.createElementNS("http://www.w3.org/2000/svg", "path");
-
-  function pointAtLength(string) {
-      pathElement.setAttribute("d", string);
-
-      var point = pathElement.getPointAtLength(700);
-      return [Math.round(point.x), Math.round(point.y)];
-  }
-
-  assert_array_equals(pointAtLength('M0,20 L400,20 L640,20'), [640, 20]);
-  assert_array_equals(pointAtLength('M0,20 L400,20 L640,20 z'), [580, 20]);
-  assert_array_equals(pointAtLength('M0,20 L400,20 z M 320,20 L640,20'), [100, 20]);
-  assert_array_equals(pointAtLength('M0,20 L20,40'), [20, 40]);
-}, document.title + " with SVGPathElement");
-
-test(function() {
-  var rectElement = document.createElementNS("http://www.w3.org/2000/svg", "rect");
-
-  function pointAtLength(rx, ry, width, height) {
-    rectElement.setAttribute("rx", rx);
-    rectElement.setAttribute("ry", ry);
-    rectElement.setAttribute("width", width);
-    rectElement.setAttribute("height", height);
-
-    var point = rectElement.getPointAtLength(300);
-    return [Math.round(point.x), Math.round(point.y)];
-  }
-
-  assert_array_equals(pointAtLength(0, 0, 200, 300), [0, 0]);
-  assert_array_equals(pointAtLength(50, 50, 200, 300), [0, 0]);
-}, document.title + " with SVGRectElement");
-
-test(function() {
-  var circleElement = document.createElementNS("http://www.w3.org/2000/svg", "circle");
-
-  function pointAtLength(radius) {
-    circleElement.setAttribute("r", radius);
-
-    var point = circleElement.getPointAtLength(100);
-    return [Math.round(point.x), Math.round(point.y)];
-  }
-  
-  assert_array_equals(pointAtLength(10), [0, 0]);
-  assert_array_equals(pointAtLength(100), [0, 0]);
-}, document.title + " with SVGCircleElement");
-</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/svg/dom/SVGPolygonElement-baseVal-list-removal-crash.html b/third_party/blink/web_tests/svg/dom/SVGPolygonElement-baseVal-list-removal-crash.html
index e88e80cd..14fd21b1 100644
--- a/third_party/blink/web_tests/svg/dom/SVGPolygonElement-baseVal-list-removal-crash.html
+++ b/third_party/blink/web_tests/svg/dom/SVGPolygonElement-baseVal-list-removal-crash.html
@@ -6,8 +6,8 @@
 
 function go() {
     var oSVGPolygon = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
-    var oSVGPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
-    var oSVGPoint1 = oSVGPath.getPointAtLength(0.0);
+    var svgRoot = document.createElementNS("http://www.w3.org/2000/svg", "svg");
+    var oSVGPoint1 = svgRoot.createSVGPoint();
     oSVGPolygon.points.initialize(oSVGPoint1);
     oSVGPolygon.points.removeItem(-9223372036854775802);
     alert("Accessing old oSVGPoint1.x: " + oSVGPoint1.x);
diff --git a/tools/android/asan/third_party/README.chromium b/tools/android/asan/third_party/README.chromium
index c35bff0..45d6e0d 100644
--- a/tools/android/asan/third_party/README.chromium
+++ b/tools/android/asan/third_party/README.chromium
@@ -5,3 +5,6 @@
 Security Critical: no
 
 asan_device_setup.sh is a verbatim copy of asan_device_setup in the LLVM trunk.
+
+Local Modifications:
+ * Patched in https://reviews.llvm.org/D84237
diff --git a/tools/android/asan/third_party/asan_device_setup.sh b/tools/android/asan/third_party/asan_device_setup.sh
index 041bf92..27fedea 100755
--- a/tools/android/asan/third_party/asan_device_setup.sh
+++ b/tools/android/asan/third_party/asan_device_setup.sh
@@ -330,7 +330,7 @@
 ASAN_OPTIONS=$ASAN_OPTIONS \\
 ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \\
 LD_PRELOAD=$_ld_preload \\
-exec $_to \$@
+exec $_to "\$@"
 
 EOF
 }
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 2150cc5..5e315b8 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -28367,7 +28367,7 @@
   <int value="3210" label="LegacyLayoutByFlexBox"/>
   <int value="3211" label="LegacyLayoutByFrameSet"/>
   <int value="3212" label="LegacyLayoutByGrid"/>
-  <int value="3213" label="LegacyLayoutByMenuList"/>
+  <int value="3213" label="OBSOLETE_LegacyLayoutByMenuList"/>
   <int value="3214" label="LegacyLayoutByMultiCol"/>
   <int value="3215" label="LegacyLayoutByPrinting"/>
   <int value="3216" label="LegacyLayoutByRuby"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index dacab0d..0616c4f0 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -103959,7 +103959,7 @@
 </histogram>
 
 <histogram name="Net.WebSocket.CloseCode" enum="WebSocketCloseCode"
-    expires_after="M86">
+    expires_after="2020-12-01">
   <owner>ricea@chromium.org</owner>
   <owner>yhirano@chromium.org</owner>
   <owner>yoichio@chromium.org</owner>
@@ -125861,9 +125861,9 @@
 </histogram>
 
 <histogram name="PasswordManager.OsPasswordStatus"
-    enum="PasswordManagerOsPasswordStatus" expires_after="M83">
-  <owner>battre@chromium.org</owner>
-  <owner>wfh@chromium.org</owner>
+    enum="PasswordManagerOsPasswordStatus" expires_after="2020-12-12">
+  <owner>vasilii@chromium.org</owner>
+  <owner>jdoerrie@chromium.org</owner>
   <summary>
     Indicates whether the user's OS password is blank or not at browser startup.
   </summary>
@@ -151426,7 +151426,7 @@
 </histogram>
 
 <histogram name="Scheduler.CancelableTaskTracker.TaskDuration2" units="ms"
-    expires_after="2020-08-01">
+    expires_after="2020-12-01">
 <!-- Name completed by histogram_suffixes name="CancelableTaskTrackerDurationTypes" -->
 
   <owner>wez@chromium.org</owner>
@@ -151438,7 +151438,7 @@
 </histogram>
 
 <histogram name="Scheduler.CancelableTaskTracker.TaskStatus"
-    enum="CancelableTaskStatus" expires_after="2020-08-01">
+    enum="CancelableTaskStatus" expires_after="2020-12-01">
   <owner>wez@chromium.org</owner>
   <owner>scheduler-dev@chromium.org</owner>
   <summary>
diff --git a/ui/accessibility/ax_enum_util.cc b/ui/accessibility/ax_enum_util.cc
index 71cc205..c9fdf449 100644
--- a/ui/accessibility/ax_enum_util.cc
+++ b/ui/accessibility/ax_enum_util.cc
@@ -2349,35 +2349,35 @@
   return ax::mojom::TextAlign::kNone;
 }
 
-const char* ToString(ax::mojom::TextDirection text_direction) {
+const char* ToString(ax::mojom::WritingDirection text_direction) {
   switch (text_direction) {
-    case ax::mojom::TextDirection::kNone:
+    case ax::mojom::WritingDirection::kNone:
       return "none";
-    case ax::mojom::TextDirection::kLtr:
+    case ax::mojom::WritingDirection::kLtr:
       return "ltr";
-    case ax::mojom::TextDirection::kRtl:
+    case ax::mojom::WritingDirection::kRtl:
       return "rtl";
-    case ax::mojom::TextDirection::kTtb:
+    case ax::mojom::WritingDirection::kTtb:
       return "ttb";
-    case ax::mojom::TextDirection::kBtt:
+    case ax::mojom::WritingDirection::kBtt:
       return "btt";
   }
 
   return "";
 }
 
-ax::mojom::TextDirection ParseTextDirection(const char* text_direction) {
+ax::mojom::WritingDirection ParseTextDirection(const char* text_direction) {
   if (0 == strcmp(text_direction, "none"))
-    return ax::mojom::TextDirection::kNone;
+    return ax::mojom::WritingDirection::kNone;
   if (0 == strcmp(text_direction, "ltr"))
-    return ax::mojom::TextDirection::kLtr;
+    return ax::mojom::WritingDirection::kLtr;
   if (0 == strcmp(text_direction, "rtl"))
-    return ax::mojom::TextDirection::kRtl;
+    return ax::mojom::WritingDirection::kRtl;
   if (0 == strcmp(text_direction, "ttb"))
-    return ax::mojom::TextDirection::kTtb;
+    return ax::mojom::WritingDirection::kTtb;
   if (0 == strcmp(text_direction, "btt"))
-    return ax::mojom::TextDirection::kBtt;
-  return ax::mojom::TextDirection::kNone;
+    return ax::mojom::WritingDirection::kBtt;
+  return ax::mojom::WritingDirection::kNone;
 }
 
 const char* ToString(ax::mojom::TextPosition text_position) {
diff --git a/ui/accessibility/ax_enum_util.h b/ui/accessibility/ax_enum_util.h
index 7ed3e88..154a26e8 100644
--- a/ui/accessibility/ax_enum_util.h
+++ b/ui/accessibility/ax_enum_util.h
@@ -113,9 +113,9 @@
 AX_BASE_EXPORT const char* ToString(ax::mojom::TextAlign text_align);
 AX_BASE_EXPORT ax::mojom::TextAlign ParseTextAlign(const char* text_align);
 
-// ax::mojom::TextDirection
-AX_BASE_EXPORT const char* ToString(ax::mojom::TextDirection text_direction);
-AX_BASE_EXPORT ax::mojom::TextDirection ParseTextDirection(
+// ax::mojom::WritingDirection
+AX_BASE_EXPORT const char* ToString(ax::mojom::WritingDirection text_direction);
+AX_BASE_EXPORT ax::mojom::WritingDirection ParseTextDirection(
     const char* text_direction);
 
 // ax::mojom::TextPosition
diff --git a/ui/accessibility/ax_enum_util_unittest.cc b/ui/accessibility/ax_enum_util_unittest.cc
index d0cca6b..b0b0c7d 100644
--- a/ui/accessibility/ax_enum_util_unittest.cc
+++ b/ui/accessibility/ax_enum_util_unittest.cc
@@ -173,7 +173,7 @@
 }
 
 TEST(AXEnumUtilTest, TextDirection) {
-  TestEnumStringConversion<ax::mojom::TextDirection>(ParseTextDirection);
+  TestEnumStringConversion<ax::mojom::WritingDirection>(ParseTextDirection);
 }
 
 TEST(AXEnumUtilTest, TextPosition) {
diff --git a/ui/accessibility/ax_enums.mojom b/ui/accessibility/ax_enums.mojom
index 2b34744..82370df 100644
--- a/ui/accessibility/ax_enums.mojom
+++ b/ui/accessibility/ax_enums.mojom
@@ -906,7 +906,7 @@
   kJustify,
 };
 
-enum TextDirection {
+enum WritingDirection {
   kNone,
   kLtr,
   kRtl,
diff --git a/ui/accessibility/ax_event_generator_unittest.cc b/ui/accessibility/ax_event_generator_unittest.cc
index 9387a99..ad755374 100644
--- a/ui/accessibility/ax_event_generator_unittest.cc
+++ b/ui/accessibility/ax_event_generator_unittest.cc
@@ -728,7 +728,7 @@
   update.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor, 0);
   update.nodes[3].AddIntAttribute(
       ax::mojom::IntAttribute::kTextDirection,
-      static_cast<int32_t>(ax::mojom::TextDirection::kRtl));
+      static_cast<int32_t>(ax::mojom::WritingDirection::kRtl));
   update.nodes[4].AddIntAttribute(
       ax::mojom::IntAttribute::kTextPosition,
       static_cast<int32_t>(ax::mojom::TextPosition::kSuperscript));
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc
index a39643db..444960b 100644
--- a/ui/accessibility/ax_node_data.cc
+++ b/ui/accessibility/ax_node_data.cc
@@ -904,15 +904,15 @@
                   static_cast<int32_t>(text_align));
 }
 
-ax::mojom::TextDirection AXNodeData::GetTextDirection() const {
-  return static_cast<ax::mojom::TextDirection>(
+ax::mojom::WritingDirection AXNodeData::GetTextDirection() const {
+  return static_cast<ax::mojom::WritingDirection>(
       GetIntAttribute(ax::mojom::IntAttribute::kTextDirection));
 }
 
-void AXNodeData::SetTextDirection(ax::mojom::TextDirection text_direction) {
+void AXNodeData::SetTextDirection(ax::mojom::WritingDirection text_direction) {
   if (HasIntAttribute(ax::mojom::IntAttribute::kTextDirection))
     RemoveIntAttribute(ax::mojom::IntAttribute::kTextDirection);
-  if (text_direction != ax::mojom::TextDirection::kNone) {
+  if (text_direction != ax::mojom::WritingDirection::kNone) {
     AddIntAttribute(ax::mojom::IntAttribute::kTextDirection,
                     static_cast<int32_t>(text_direction));
   }
@@ -1260,17 +1260,18 @@
             static_cast<ax::mojom::TextAlign>(int_attribute.second));
         break;
       case ax::mojom::IntAttribute::kTextDirection:
-        switch (static_cast<ax::mojom::TextDirection>(int_attribute.second)) {
-          case ax::mojom::TextDirection::kLtr:
+        switch (
+            static_cast<ax::mojom::WritingDirection>(int_attribute.second)) {
+          case ax::mojom::WritingDirection::kLtr:
             result += " text_direction=ltr";
             break;
-          case ax::mojom::TextDirection::kRtl:
+          case ax::mojom::WritingDirection::kRtl:
             result += " text_direction=rtl";
             break;
-          case ax::mojom::TextDirection::kTtb:
+          case ax::mojom::WritingDirection::kTtb:
             result += " text_direction=ttb";
             break;
-          case ax::mojom::TextDirection::kBtt:
+          case ax::mojom::WritingDirection::kBtt:
             result += " text_direction=btt";
             break;
           default:
diff --git a/ui/accessibility/ax_node_data.h b/ui/accessibility/ax_node_data.h
index 9f70e4a..a531f40 100644
--- a/ui/accessibility/ax_node_data.h
+++ b/ui/accessibility/ax_node_data.h
@@ -196,8 +196,8 @@
   void SetListStyle(ax::mojom::ListStyle list_style);
   ax::mojom::TextAlign GetTextAlign() const;
   void SetTextAlign(ax::mojom::TextAlign text_align);
-  ax::mojom::TextDirection GetTextDirection() const;
-  void SetTextDirection(ax::mojom::TextDirection text_direction);
+  ax::mojom::WritingDirection GetTextDirection() const;
+  void SetTextDirection(ax::mojom::WritingDirection text_direction);
   ax::mojom::ImageAnnotationStatus GetImageAnnotationStatus() const;
   void SetImageAnnotationStatus(ax::mojom::ImageAnnotationStatus status);
 
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
index 4f4614f..1be154f 100644
--- a/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -2082,21 +2082,21 @@
     attributes.push_back(std::make_pair("language", language));
   }
 
-  auto text_direction = static_cast<ax::mojom::TextDirection>(
+  auto text_direction = static_cast<ax::mojom::WritingDirection>(
       GetIntAttribute(ax::mojom::IntAttribute::kTextDirection));
   switch (text_direction) {
-    case ax::mojom::TextDirection::kNone:
+    case ax::mojom::WritingDirection::kNone:
       break;
-    case ax::mojom::TextDirection::kLtr:
+    case ax::mojom::WritingDirection::kLtr:
       attributes.push_back(std::make_pair("writing-mode", "lr"));
       break;
-    case ax::mojom::TextDirection::kRtl:
+    case ax::mojom::WritingDirection::kRtl:
       attributes.push_back(std::make_pair("writing-mode", "rl"));
       break;
-    case ax::mojom::TextDirection::kTtb:
+    case ax::mojom::WritingDirection::kTtb:
       attributes.push_back(std::make_pair("writing-mode", "tb"));
       break;
-    case ax::mojom::TextDirection::kBtt:
+    case ax::mojom::WritingDirection::kBtt:
       // Not listed in the IA2 Spec.
       attributes.push_back(std::make_pair("writing-mode", "bt"));
       break;
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
index 6e744360..e1925cff6 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -3616,7 +3616,7 @@
                             0xDEADBEEFU);
   text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU);
   text_data.AddStringAttribute(ax::mojom::StringAttribute::kLanguage, "fr-CA");
-  text_data.SetTextDirection(ax::mojom::TextDirection::kRtl);
+  text_data.SetTextDirection(ax::mojom::WritingDirection::kRtl);
   text_data.AddTextStyle(ax::mojom::TextStyle::kItalic);
   text_data.SetTextPosition(ax::mojom::TextPosition::kSubscript);
   text_data.SetRestriction(ax::mojom::Restriction::kReadOnly);
@@ -3637,7 +3637,7 @@
   heading_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
                                0xDEADBEEFU);
   heading_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU);
-  heading_data.SetTextDirection(ax::mojom::TextDirection::kRtl);
+  heading_data.SetTextDirection(ax::mojom::WritingDirection::kRtl);
   heading_data.SetTextPosition(ax::mojom::TextPosition::kSuperscript);
   heading_data.AddState(ax::mojom::State::kEditable);
   heading_data.child_ids = {4};
@@ -3650,7 +3650,7 @@
                                     0xDEADBEEFU);
   heading_text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor,
                                     0xDEADC0DEU);
-  heading_text_data.SetTextDirection(ax::mojom::TextDirection::kRtl);
+  heading_text_data.SetTextDirection(ax::mojom::WritingDirection::kRtl);
   heading_text_data.SetTextPosition(ax::mojom::TextPosition::kSuperscript);
   heading_text_data.AddState(ax::mojom::State::kEditable);
   heading_text_data.SetTextAlign(ax::mojom::TextAlign::kJustify);
@@ -3669,7 +3669,7 @@
   mark_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
                             0xDEADBEEFU);
   mark_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU);
-  mark_data.SetTextDirection(ax::mojom::TextDirection::kRtl);
+  mark_data.SetTextDirection(ax::mojom::WritingDirection::kRtl);
   mark_data.child_ids = {6};
 
   ui::AXNodeData mark_text_data;
@@ -3678,7 +3678,7 @@
   mark_text_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
                                  0xDEADBEEFU);
   mark_text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU);
-  mark_text_data.SetTextDirection(ax::mojom::TextDirection::kRtl);
+  mark_text_data.SetTextDirection(ax::mojom::WritingDirection::kRtl);
   mark_text_data.SetTextAlign(ax::mojom::TextAlign::kNone);
   mark_text_data.SetName("marked text");
 
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 369c61a..06fc94c7 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -4879,17 +4879,17 @@
 
 // static
 FlowDirections AXPlatformNodeWin::TextDirectionToFlowDirections(
-    ax::mojom::TextDirection text_direction) {
+    ax::mojom::WritingDirection text_direction) {
   switch (text_direction) {
-    case ax::mojom::TextDirection::kNone:
+    case ax::mojom::WritingDirection::kNone:
       return FlowDirections::FlowDirections_Default;
-    case ax::mojom::TextDirection::kLtr:
+    case ax::mojom::WritingDirection::kLtr:
       return FlowDirections::FlowDirections_Default;
-    case ax::mojom::TextDirection::kRtl:
+    case ax::mojom::WritingDirection::kRtl:
       return FlowDirections::FlowDirections_RightToLeft;
-    case ax::mojom::TextDirection::kTtb:
+    case ax::mojom::WritingDirection::kTtb:
       return FlowDirections::FlowDirections_Vertical;
-    case ax::mojom::TextDirection::kBtt:
+    case ax::mojom::WritingDirection::kBtt:
       return FlowDirections::FlowDirections_BottomToTop;
   }
 }
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h
index 682149b..ef1959b 100644
--- a/ui/accessibility/platform/ax_platform_node_win.h
+++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -1374,7 +1374,8 @@
   // Converts a ListStyle to UIA StyleId enumeration
   static LONG AXListStyleToUIAStyleId(ax::mojom::ListStyle list_style);
   // Convert mojom TextDirection to UIA FlowDirections enumeration
-  static FlowDirections TextDirectionToFlowDirections(ax::mojom::TextDirection);
+  static FlowDirections TextDirectionToFlowDirections(
+      ax::mojom::WritingDirection);
 
   // Helper method for |GetMarkerTypeFromRange| which aggregates all
   // of the ranges for |marker_type| attached to |node|.
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc
index 873ab5c..45d3274a 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.cc
+++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -966,11 +966,11 @@
   gfx::RectF location = GetLocation();
   gfx::RectF bounds;
 
-  switch (static_cast<ax::mojom::TextDirection>(
+  switch (static_cast<ax::mojom::WritingDirection>(
       GetData().GetIntAttribute(ax::mojom::IntAttribute::kTextDirection))) {
     // Currently only kNone and kLtr are supported text direction.
-    case ax::mojom::TextDirection::kNone:
-    case ax::mojom::TextDirection::kLtr: {
+    case ax::mojom::WritingDirection::kNone:
+    case ax::mojom::WritingDirection::kLtr: {
       int start_pixel_offset =
           start_offset > 0 ? character_offsets[start_offset - 1] : location.x();
       int end_pixel_offset =
diff --git a/ui/accessibility/test_ax_node_helper.cc b/ui/accessibility/test_ax_node_helper.cc
index ba257f7..a2cfcf0 100644
--- a/ui/accessibility/test_ax_node_helper.cc
+++ b/ui/accessibility/test_ax_node_helper.cc
@@ -158,11 +158,11 @@
   gfx::RectF location = GetLocation();
   gfx::RectF bounds;
 
-  switch (static_cast<ax::mojom::TextDirection>(
+  switch (static_cast<ax::mojom::WritingDirection>(
       GetData().GetIntAttribute(ax::mojom::IntAttribute::kTextDirection))) {
     // Currently only kNone and kLtr are supported text direction.
-    case ax::mojom::TextDirection::kNone:
-    case ax::mojom::TextDirection::kLtr: {
+    case ax::mojom::WritingDirection::kNone:
+    case ax::mojom::WritingDirection::kLtr: {
       int start_pixel_offset =
           start_offset > 0 ? character_offsets[start_offset - 1] : location.x();
       int end_pixel_offset =
diff --git a/ui/base/clipboard/clipboard_non_backed.cc b/ui/base/clipboard/clipboard_non_backed.cc
index f2a1922..29c632b3 100644
--- a/ui/base/clipboard/clipboard_non_backed.cc
+++ b/ui/base/clipboard/clipboard_non_backed.cc
@@ -33,14 +33,8 @@
 
 namespace ui {
 
-namespace {
-
-const size_t kMaxClipboardSize = 1;
-
-}  // namespace
-
 // Simple, internal implementation of a clipboard, handling things like format
-// conversion, versioning, etc.
+// conversion, sequence numbers, etc.
 class ClipboardInternal {
  public:
   ClipboardInternal() = default;
@@ -48,41 +42,35 @@
   ~ClipboardInternal() = default;
 
   void Clear() {
-    sequence_number_++;
-    data_list_.clear();
+    ++sequence_number_;
+    data_.reset();
     ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();
   }
 
   uint64_t sequence_number() const { return sequence_number_; }
 
-  // Returns the data currently on the top of the clipboard stack, nullptr if
-  // the clipboard stack is empty.
-  const ClipboardData* GetData() const {
-    if (data_list_.empty())
-      return nullptr;
-    return data_list_.front().get();
-  }
+  // Returns the current clipboard data, which may be nullptr if nothing has
+  // been written since the last Clear().
+  const ClipboardData* GetData() const { return data_.get(); }
 
   // Returns true if the data on top of the clipboard stack has format |format|
   // or another format that can be converted to |format|.
   bool IsFormatAvailable(ClipboardInternalFormat format) const {
-    switch (format) {
-      case ClipboardInternalFormat::kText:
-        return HasFormat(ClipboardInternalFormat::kText) ||
-               HasFormat(ClipboardInternalFormat::kBookmark);
-      default:
-        return HasFormat(format);
+    if (format == ClipboardInternalFormat::kText) {
+      return HasFormat(ClipboardInternalFormat::kText) ||
+             HasFormat(ClipboardInternalFormat::kBookmark);
     }
+    return HasFormat(format);
   }
 
-  // Reads text from the data at the top of clipboard stack.
+  // Reads text from the ClipboardData.
   void ReadText(base::string16* result) const {
     std::string utf8_result;
     ReadAsciiText(&utf8_result);
     *result = base::UTF8ToUTF16(utf8_result);
   }
 
-  // Reads ASCII text from the data at the top of clipboard stack.
+  // Reads ASCII text from the ClipboardData.
   void ReadAsciiText(std::string* result) const {
     result->clear();
     const ClipboardData* data = GetData();
@@ -96,7 +84,7 @@
       *result = data->bookmark_url();
   }
 
-  // Reads HTML from the data at the top of clipboard stack.
+  // Reads HTML from the ClipboardData.
   void ReadHTML(base::string16* markup,
                 std::string* src_url,
                 uint32_t* fragment_start,
@@ -119,7 +107,7 @@
     *fragment_end = static_cast<uint32_t>(markup->length());
   }
 
-  // Reads RTF from the data at the top of clipboard stack.
+  // Reads RTF from the ClipboardData.
   void ReadRTF(std::string* result) const {
     result->clear();
     const ClipboardData* data = GetData();
@@ -129,7 +117,7 @@
     *result = data->rtf_data();
   }
 
-  // Reads image from the data at the top of clipboard stack.
+  // Reads image from the ClipboardData.
   SkBitmap ReadImage() const {
     SkBitmap img;
     if (!HasFormat(ClipboardInternalFormat::kBitmap))
@@ -144,7 +132,7 @@
     return img;
   }
 
-  // Reads data of type |type| from the data at the top of clipboard stack.
+  // Reads data of type |type| from the ClipboardData.
   void ReadCustomData(const base::string16& type,
                       base::string16* result) const {
     result->clear();
@@ -156,7 +144,7 @@
                           data->custom_data_data().size(), type, result);
   }
 
-  // Reads bookmark from the data at the top of clipboard stack.
+  // Reads bookmark from the ClipboardData.
   void ReadBookmark(base::string16* title, std::string* url) const {
     if (title)
       title->clear();
@@ -182,10 +170,11 @@
     *result = data->custom_data_data();
   }
 
-  // Writes |data| to the top of the clipboard stack.
+  // Writes |data| to the ClipboardData.
   void WriteData(std::unique_ptr<ClipboardData> data) {
     DCHECK(data);
-    AddToListEnsuringSize(std::move(data));
+    ++sequence_number_;
+    data_ = std::move(data);
     ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();
   }
 
@@ -201,26 +190,14 @@
   }
 
  private:
-  // True if the data on top of the clipboard stack has format |format|.
+  // True if the ClipboardData has format |format|.
   bool HasFormat(ClipboardInternalFormat format) const {
     const ClipboardData* data = GetData();
     return data ? data->format() & static_cast<int>(format) : false;
   }
 
-  void AddToListEnsuringSize(std::unique_ptr<ClipboardData> data) {
-    DCHECK(data);
-    sequence_number_++;
-    data_list_.push_front(std::move(data));
-
-    // If the size of list becomes more than the maximum allowed, we delete the
-    // last element.
-    if (data_list_.size() > kMaxClipboardSize) {
-      data_list_.pop_back();
-    }
-  }
-
-  // Stack containing various versions of ClipboardData.
-  std::list<std::unique_ptr<ClipboardData>> data_list_;
+  // Current ClipboardData.
+  std::unique_ptr<ClipboardData> data_;
 
   // Sequence number uniquely identifying clipboard state.
   uint64_t sequence_number_ = 0;
diff --git a/ui/latency/latency_info.dot b/ui/latency/latency_info.dot
index 3490ac1..887d4e9 100644
--- a/ui/latency/latency_info.dot
+++ b/ui/latency/latency_info.dot
@@ -8,8 +8,6 @@
     node[style="dotted,rounded"];
 
     "Event.Latency.EventToRender.TouchpadPinch";
-    "Event.Latency.QueueingTime.<event_name><default_action_status>";
-    "Event.Latency.BlockingTime.<event_name><default_action_status>";
     end_to_end_metrics
       [label="\
 Event.Latency.EndToEnd.KeyPress\n\
@@ -56,11 +54,7 @@
   // Layout the rest of the components.
   INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT->
   "Event.Latency.EventToRender.TouchpadPinch"->
-  INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT->
-  "Event.Latency.QueueingTime.<event_name><default_action_status>"->
-  INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT->
-  "Event.Latency.BlockingTime.<event_name><default_action_status>"->
-  INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT
+  INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT
     [weight=3];
 
   INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT->
@@ -94,7 +88,7 @@
   "Event.Latency.<scroll_name>.Touch.RAFTimeToFrameSwapEnd"->
   INPUT_EVENT_LATENCY_FRAME_SWAP_COMPONENT;
 
-  // Add legend and position it under INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT.
+  // Add legend and position it under INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT.
   legend
     [shape=plaintext,label="\
 LEGEND:\l\
@@ -102,7 +96,7 @@
   <input_modality> = (Wheel | Touch)\l\
   <scroll_name> = (ScrollBegin | ScrollUpdate)\l\
   <thread_name> = (Main | Impl)\l"];
-  INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT->
+  INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT->
   legend
-    [style=invis,minlen=3];
+    [style=invis,minlen=7];
 }
diff --git a/ui/ozone/platform/wayland/common/wayland_util.cc b/ui/ozone/platform/wayland/common/wayland_util.cc
index 14593b1..19d33ef4 100644
--- a/ui/ozone/platform/wayland/common/wayland_util.cc
+++ b/ui/ozone/platform/wayland/common/wayland_util.cc
@@ -10,6 +10,8 @@
 #include "ui/base/hit_test.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_shm_buffer.h"
+#include "ui/ozone/platform/wayland/host/wayland_surface.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
 
 namespace wl {
 
@@ -160,4 +162,14 @@
          type == ui::PlatformWindowType::kPopup;
 }
 
+ui::WaylandWindow* RootWindowFromWlSurface(wl_surface* surface) {
+  if (!surface)
+    return nullptr;
+  auto* wayland_surface = static_cast<ui::WaylandSurface*>(
+      wl_proxy_get_user_data(reinterpret_cast<wl_proxy*>(surface)));
+  if (!wayland_surface)
+    return nullptr;
+  return wayland_surface->root_window();
+}
+
 }  // namespace wl
diff --git a/ui/ozone/platform/wayland/common/wayland_util.h b/ui/ozone/platform/wayland/common/wayland_util.h
index 3db3696..918f4c6 100644
--- a/ui/ozone/platform/wayland/common/wayland_util.h
+++ b/ui/ozone/platform/wayland/common/wayland_util.h
@@ -22,6 +22,7 @@
 namespace ui {
 class WaylandConnection;
 class WaylandShmBuffer;
+class WaylandWindow;
 }  // namespace ui
 
 namespace gfx {
@@ -62,6 +63,9 @@
 // Says if the type is kPopup or kMenu.
 bool IsMenuType(ui::PlatformWindowType type);
 
+// Returns the root WaylandWindow for the given wl_surface.
+ui::WaylandWindow* RootWindowFromWlSurface(wl_surface* surface);
+
 }  // namespace wl
 
 #endif  // UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_
diff --git a/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc b/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc
index 02ec5b80..e5cdaf1 100644
--- a/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc
@@ -21,8 +21,8 @@
 std::unique_ptr<wl_egl_window, EGLWindowDeleter> CreateWaylandEglWindow(
     WaylandWindow* window) {
   gfx::Size size = window->GetBounds().size();
-  return std::unique_ptr<wl_egl_window, EGLWindowDeleter>(
-      wl_egl_window_create(window->surface(), size.width(), size.height()));
+  return std::unique_ptr<wl_egl_window, EGLWindowDeleter>(wl_egl_window_create(
+      window->root_surface()->surface(), size.width(), size.height()));
 }
 
 GLSurfaceWayland::GLSurfaceWayland(WaylandEglWindowPtr egl_window)
diff --git a/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc b/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc
index 0a1d243..9575fe7 100644
--- a/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc
@@ -68,7 +68,7 @@
       GetBounds(), parent_window()->GetBounds(), ui_scale(), buffer_scale());
   wl_subsurface_set_position(subsurface_.get(), bounds_px.x() / buffer_scale(),
                              bounds_px.y() / buffer_scale());
-  wl_surface_commit(surface());
+  root_surface()->Commit();
   connection()->ScheduleFlush();
 }
 
@@ -97,10 +97,7 @@
   if (!parent)
     return;
 
-  wl_subcompositor* subcompositor = connection()->subcompositor();
-  DCHECK(subcompositor);
-  subsurface_.reset(wl_subcompositor_get_subsurface(subcompositor, surface(),
-                                                    parent->surface()));
+  subsurface_ = root_surface()->CreateSubsurface(parent->root_surface());
 
   // Chromium positions tooltip windows in screen coordinates, but Wayland
   // requires them to be in local surface coordinates a.k.a relative to parent
@@ -113,7 +110,7 @@
   wl_subsurface_set_position(subsurface_.get(), bounds_px.x() / buffer_scale(),
                              bounds_px.y() / buffer_scale());
   wl_subsurface_set_desync(subsurface_.get());
-  wl_surface_commit(parent->surface());
+  parent->root_surface()->Commit();
   connection()->ScheduleFlush();
 
   // Notify the observers the window has been configured. Please note that
diff --git a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
index 6e2f2d7..4e6dd950d 100644
--- a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
@@ -153,8 +153,8 @@
     if (!wayland_surface_)
       return;
 
-    wl_surface_attach(wayland_surface_->surface(), nullptr, 0, 0);
-    wl_surface_commit(wayland_surface_->surface());
+    wayland_surface_->AttachBuffer(nullptr);
+    wayland_surface_->Commit();
 
     // ResetSurfaceContents happens upon WaylandWindow::Hide call, which
     // destroys xdg_surface, xdg_popup, etc. They are going to be reinitialized
@@ -251,48 +251,17 @@
       pending_damage_region.set_size(buffer->size);
     DCHECK(!pending_damage_region.size().IsEmpty());
 
-    if (connection_->compositor_version() >=
-        WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) {
-      // wl_surface_damage_buffer relies on compositor API version 4. See
-      // https://bit.ly/2u00lv6 for details.
-      // We don't need to apply any scaling because pending_damage_region is
-      // already in buffer coordinates.
-      wl_surface_damage_buffer(
-          wayland_surface_->surface(), pending_damage_region.x(),
-          pending_damage_region.y(), pending_damage_region.width(),
-          pending_damage_region.height());
-    } else {
-      // The calculation for damage region relies on two assumptions:
-      // 1) The buffer is always attached at surface location (0, 0)
-      // 2) The API wl_surface::set_buffer_transform is not used.
-      // It's possible to write logic that accounts for both cases above, but
-      // it's currently unnecessary.
-      //
-      // Note: The damage region may not be an integer multiple of scale. To
-      // keep the implementation simple, the x() and y() coordinates round down,
-      // and the width() and height() calculations always add an extra pixel.
-      int scale = wayland_surface_->buffer_scale();
-      wl_surface_damage(wayland_surface_->surface(),
-                        pending_damage_region.x() / scale,
-                        pending_damage_region.y() / scale,
-                        pending_damage_region.width() / scale + 1,
-                        pending_damage_region.height() / scale + 1);
-    }
+    wayland_surface_->Damage(pending_damage_region);
   }
 
   void AttachBuffer(WaylandBuffer* buffer) {
     DCHECK(wayland_surface_ && configured_);
-
-    // The logic in DamageBuffer currently relies on attachment coordinates of
-    // (0, 0). If this changes, then the calculation in DamageBuffer will also
-    // need to be updated.
-    wl_surface_attach(wayland_surface_->surface(), buffer->wl_buffer.get(), 0,
-                      0);
+    wayland_surface_->AttachBuffer(buffer->wl_buffer.get());
   }
 
   void CommitSurface() {
     DCHECK(wayland_surface_);
-    wl_surface_commit(wayland_surface_->surface());
+    wayland_surface_->Commit();
   }
 
   void SetupFrameCallback() {
@@ -569,8 +538,8 @@
   // Widget this helper surface backs and has 1:1 relationship with the
   // WaylandWindow.
 
-  // Non-owned. The window this helper surface stores and submits buffers for.
-  const WaylandSurface* wayland_surface_;
+  // Non-owned. The surface this helper stores and submits buffers for.
+  WaylandSurface* wayland_surface_;
 
   // Non-owned pointer to the connection.
   WaylandConnection* const connection_;
@@ -624,7 +593,7 @@
 void WaylandBufferManagerHost::OnWindowAdded(WaylandWindow* window) {
   DCHECK(window);
   surfaces_[window->GetWidget()] =
-      std::make_unique<Surface>(window->wayland_surface(), connection_, this);
+      std::make_unique<Surface>(window->root_surface(), connection_, this);
 }
 
 void WaylandBufferManagerHost::OnWindowRemoved(WaylandWindow* window) {
diff --git a/ui/ozone/platform/wayland/host/wayland_data_device.cc b/ui/ozone/platform/wayland/host/wayland_data_device.cc
index edbb6d472..932b1e4 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_device.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_device.cc
@@ -43,8 +43,8 @@
   drag_delegate_ = delegate;
 
   wl_data_device_start_drag(data_device_.get(), data_source.data_source(),
-                            origin_window.surface(), icon_surface,
-                            connection()->serial());
+                            origin_window.root_surface()->surface(),
+                            icon_surface, connection()->serial());
   drag_delegate_->DrawIcon();
   connection()->ScheduleFlush();
 }
@@ -109,7 +109,7 @@
                                 wl_fixed_t x,
                                 wl_fixed_t y,
                                 wl_data_offer* offer) {
-  WaylandWindow* window = WaylandWindow::FromSurface(surface);
+  WaylandWindow* window = wl::RootWindowFromWlSurface(surface);
   if (!window) {
     LOG(ERROR) << "Failed to get window.";
     return;
diff --git a/ui/ozone/platform/wayland/host/wayland_keyboard.cc b/ui/ozone/platform/wayland/host/wayland_keyboard.cc
index 7de0fe69..a4c905b 100644
--- a/ui/ozone/platform/wayland/host/wayland_keyboard.cc
+++ b/ui/ozone/platform/wayland/host/wayland_keyboard.cc
@@ -20,6 +20,7 @@
 #include "ui/events/ozone/layout/keyboard_layout_engine.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
 #include "ui/events/types/event_type.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_window.h"
 
@@ -101,7 +102,7 @@
                             wl_surface* surface,
                             wl_array* keys) {
   // wl_surface might have been destroyed by this time.
-  if (auto* window = WaylandWindow::FromSurface(surface)) {
+  if (auto* window = wl::RootWindowFromWlSurface(surface)) {
     auto* self = static_cast<WaylandKeyboard*>(data);
     self->delegate_->OnKeyboardFocusChanged(window, /*focused=*/true);
   }
@@ -113,7 +114,7 @@
                             wl_surface* surface) {
   // wl_surface might have been destroyed by this time.
   auto* self = static_cast<WaylandKeyboard*>(data);
-  if (auto* window = WaylandWindow::FromSurface(surface))
+  if (auto* window = wl::RootWindowFromWlSurface(surface))
     self->delegate_->OnKeyboardFocusChanged(window, /*focused=*/false);
 
   // Upon window focus lose, reset the key repeat timers.
diff --git a/ui/ozone/platform/wayland/host/wayland_pointer.cc b/ui/ozone/platform/wayland/host/wayland_pointer.cc
index 1658a68c..13cb8c0 100644
--- a/ui/ozone/platform/wayland/host/wayland_pointer.cc
+++ b/ui/ozone/platform/wayland/host/wayland_pointer.cc
@@ -10,6 +10,7 @@
 
 #include "ui/events/event.h"
 #include "ui/events/types/event_type.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_window.h"
 
@@ -45,7 +46,7 @@
                            wl_fixed_t surface_y) {
   DCHECK(data);
   WaylandPointer* pointer = static_cast<WaylandPointer*>(data);
-  WaylandWindow* window = WaylandWindow::FromSurface(surface);
+  WaylandWindow* window = wl::RootWindowFromWlSurface(surface);
   gfx::PointF location{wl_fixed_to_double(surface_x),
                        wl_fixed_to_double(surface_y)};
   pointer->delegate_->OnPointerFocusChanged(window, location);
diff --git a/ui/ozone/platform/wayland/host/wayland_popup.cc b/ui/ozone/platform/wayland/host/wayland_popup.cc
index ba52979..1fda80c5 100644
--- a/ui/ozone/platform/wayland/host/wayland_popup.cc
+++ b/ui/ozone/platform/wayland/host/wayland_popup.cc
@@ -75,7 +75,7 @@
   DCHECK(shell_popup());
   DCHECK(parent_window());
 
-  SetBufferScale(parent_window()->buffer_scale(), true);
+  root_surface()->SetBufferScale(parent_window()->buffer_scale(), true);
 
   gfx::Rect new_bounds_dip = bounds_dip;
 
@@ -138,7 +138,7 @@
     return false;
   }
   // If parent window is known in advanced, we may set the scale early.
-  SetBufferScale(parent_window()->buffer_scale(), false);
+  root_surface()->SetBufferScale(parent_window()->buffer_scale(), false);
   set_ui_scale(parent_window()->ui_scale());
   return true;
 }
diff --git a/ui/ozone/platform/wayland/host/wayland_surface.cc b/ui/ozone/platform/wayland/host/wayland_surface.cc
index 3cb2df6..f612f168 100644
--- a/ui/ozone/platform/wayland/host/wayland_surface.cc
+++ b/ui/ozone/platform/wayland/host/wayland_surface.cc
@@ -11,9 +11,16 @@
 
 WaylandSurface::WaylandSurface(WaylandConnection* connection,
                                WaylandWindow* root_window)
-    : root_window_(root_window), surface_(connection->CreateSurface()) {}
+    : connection_(connection),
+      root_window_(root_window),
+      surface_(connection->CreateSurface()) {}
 
-WaylandSurface::~WaylandSurface() = default;
+WaylandSurface::~WaylandSurface() {
+  if (surface_) {
+    wl_surface_add_listener(surface_.get(), nullptr, nullptr);
+    wl_surface_set_user_data(surface_.get(), nullptr);
+  }
+}
 
 gfx::AcceleratedWidget WaylandSurface::GetWidget() const {
   if (!surface_)
@@ -25,4 +32,111 @@
   return root_window_->GetWidget();
 }
 
+bool WaylandSurface::Initialize() {
+  if (!surface_)
+    return false;
+
+  wl_surface_set_user_data(surface_.get(), this);
+
+  static struct wl_surface_listener surface_listener = {
+      &WaylandSurface::Enter,
+      &WaylandSurface::Leave,
+  };
+  wl_surface_add_listener(surface_.get(), &surface_listener, this);
+
+  return true;
+}
+
+void WaylandSurface::AttachBuffer(wl_buffer* buffer) {
+  // The logic in DamageBuffer currently relies on attachment coordinates of
+  // (0, 0). If this changes, then the calculation in DamageBuffer will also
+  // need to be updated.
+  wl_surface_attach(surface_.get(), buffer, 0, 0);
+  connection_->ScheduleFlush();
+}
+
+void WaylandSurface::Damage(const gfx::Rect& pending_damage_region) {
+  if (connection_->compositor_version() >=
+      WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) {
+    // wl_surface_damage_buffer relies on compositor API version 4. See
+    // https://bit.ly/2u00lv6 for details.
+    // We don't need to apply any scaling because pending_damage_region is
+    // already in buffer coordinates.
+    wl_surface_damage_buffer(
+        surface_.get(), pending_damage_region.x(), pending_damage_region.y(),
+        pending_damage_region.width(), pending_damage_region.height());
+  } else {
+    // The calculation for damage region relies on two assumptions:
+    // 1) The buffer is always attached at surface location (0, 0)
+    // 2) The API wl_surface::set_buffer_transform is not used.
+    // It's possible to write logic that accounts for both cases above, but
+    // it's currently unnecessary.
+    //
+    // Note: The damage region may not be an integer multiple of scale. To
+    // keep the implementation simple, the x() and y() coordinates round down,
+    // and the width() and height() calculations always add an extra pixel.
+    wl_surface_damage(surface_.get(), pending_damage_region.x() / buffer_scale_,
+                      pending_damage_region.y() / buffer_scale_,
+                      pending_damage_region.width() / buffer_scale_ + 1,
+                      pending_damage_region.height() / buffer_scale_ + 1);
+  }
+  connection_->ScheduleFlush();
+}
+
+void WaylandSurface::Commit() {
+  wl_surface_commit(surface_.get());
+  connection_->ScheduleFlush();
+}
+
+void WaylandSurface::SetBufferScale(int32_t new_scale, bool update_bounds) {
+  DCHECK_GT(new_scale, 0);
+
+  if (new_scale == buffer_scale_)
+    return;
+
+  buffer_scale_ = new_scale;
+  wl_surface_set_buffer_scale(surface_.get(), buffer_scale_);
+  connection_->ScheduleFlush();
+}
+
+void WaylandSurface::SetBounds(const gfx::Rect& bounds_px) {
+  // It's important to set opaque region for opaque windows (provides
+  // optimization hint for the Wayland compositor).
+  if (!root_window_->IsOpaqueWindow())
+    return;
+
+  wl::Object<wl_region> region(
+      wl_compositor_create_region(connection_->compositor()));
+  wl_region_add(region.get(), 0, 0, bounds_px.width(), bounds_px.height());
+
+  wl_surface_set_opaque_region(surface_.get(), region.get());
+
+  connection_->ScheduleFlush();
+}
+
+wl::Object<wl_subsurface> WaylandSurface::CreateSubsurface(
+    WaylandSurface* parent) {
+  DCHECK(parent);
+  wl_subcompositor* subcompositor = connection_->subcompositor();
+  DCHECK(subcompositor);
+  wl::Object<wl_subsurface> subsurface(wl_subcompositor_get_subsurface(
+      subcompositor, surface_.get(), parent->surface_.get()));
+  return subsurface;
+}
+
+// static
+void WaylandSurface::Enter(void* data,
+                           struct wl_surface* wl_surface,
+                           struct wl_output* output) {
+  static_cast<WaylandSurface*>(data)->root_window_->AddEnteredOutputId(output);
+}
+
+// static
+void WaylandSurface::Leave(void* data,
+                           struct wl_surface* wl_surface,
+                           struct wl_output* output) {
+  static_cast<WaylandSurface*>(data)->root_window_->RemoveEnteredOutputId(
+      output);
+}
+
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_surface.h b/ui/ozone/platform/wayland/host/wayland_surface.h
index cfe616f..046af093 100644
--- a/ui/ozone/platform/wayland/host/wayland_surface.h
+++ b/ui/ozone/platform/wayland/host/wayland_surface.h
@@ -7,6 +7,7 @@
 
 #include <cstdint>
 
+#include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/ozone/platform/wayland/common/wayland_object.h"
 
@@ -34,13 +35,47 @@
   gfx::AcceleratedWidget GetWidget() const;
   gfx::AcceleratedWidget GetRootWidget() const;
 
+  // Initializes the WaylandSurface and returns true iff success.
+  // This may return false if a wl_surface could not be created, for example.
+  bool Initialize();
+
+  // Attaches the given wl_buffer to the underlying wl_surface at (0, 0).
+  void AttachBuffer(wl_buffer* buffer);
+
+  // Damages the surface according to |pending_damage_region|, which should be
+  // in surface coordinates (dp).
+  void Damage(const gfx::Rect& pending_damage_region);
+
+  // Commits the underlying wl_surface.
+  void Commit();
+
+  // Sets the buffer scale for this surface.
+  void SetBufferScale(int32_t scale, bool update_bounds);
+
+  // Sets the bounds on this surface. This is used for determining the opaque
+  // region.
+  void SetBounds(const gfx::Rect& bounds_px);
+
+  // Creates a wl_subsurface relating this surface and a parent surface,
+  // |parent|. Callers take ownership of the wl_subsurface.
+  wl::Object<wl_subsurface> CreateSubsurface(WaylandSurface* parent);
+
  private:
+  WaylandConnection* const connection_;
   WaylandWindow* root_window_ = nullptr;
   wl::Object<wl_surface> surface_;
 
   // Wayland's scale factor for the output that this window currently belongs
   // to.
   int32_t buffer_scale_ = 1;
+
+  // wl_surface_listener
+  static void Enter(void* data,
+                    struct wl_surface* wl_surface,
+                    struct wl_output* output);
+  static void Leave(void* data,
+                    struct wl_surface* wl_surface,
+                    struct wl_output* output);
 };
 
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_touch.cc b/ui/ozone/platform/wayland/host/wayland_touch.cc
index aff5c24..9298a43d 100644
--- a/ui/ozone/platform/wayland/host/wayland_touch.cc
+++ b/ui/ozone/platform/wayland/host/wayland_touch.cc
@@ -8,6 +8,7 @@
 
 #include "base/time/time.h"
 #include "ui/gfx/geometry/point_f.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_window.h"
 
@@ -47,7 +48,7 @@
   DCHECK(touch);
   touch->connection_->set_serial(serial);
 
-  WaylandWindow* window = WaylandWindow::FromSurface(surface);
+  WaylandWindow* window = wl::RootWindowFromWlSurface(surface);
   gfx::PointF location(wl_fixed_to_double(x), wl_fixed_to_double(y));
   base::TimeTicks timestamp =
       base::TimeTicks() + base::TimeDelta::FromMilliseconds(time);
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
index 378eb32..1e22574 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -30,24 +30,15 @@
 
 WaylandWindow::~WaylandWindow() {
   shutting_down_ = true;
-  RemoveSurfaceListener();
 
   PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
-  if (wayland_surface_)
+  if (root_surface_)
     connection_->wayland_window_manager()->RemoveWindow(GetWidget());
 
   if (parent_window_)
     parent_window_->set_child_window(nullptr);
 }
 
-// static
-WaylandWindow* WaylandWindow::FromSurface(wl_surface* surface) {
-  if (!surface)
-    return nullptr;
-  return static_cast<WaylandWindow*>(
-      wl_proxy_get_user_data(reinterpret_cast<wl_proxy*>(surface)));
-}
-
 void WaylandWindow::OnWindowLostCapture() {
   delegate_->OnLostCapture();
 }
@@ -79,12 +70,16 @@
     else
       ui_scale_ = display.device_scale_factor();
   }
-  SetBufferScale(new_scale, update_bounds);
+  // At this point, buffer_scale() still returns the old scale.
+  if (update_bounds)
+    SetBoundsDip(gfx::ScaleToRoundedRect(bounds_px_, 1.0 / buffer_scale()));
+
+  root_surface_->SetBufferScale(new_scale, update_bounds);
 }
 
 gfx::AcceleratedWidget WaylandWindow::GetWidget() const {
-  DCHECK(wayland_surface_);
-  return wayland_surface_->GetWidget();
+  DCHECK(root_surface_);
+  return root_surface_->GetWidget();
 }
 
 void WaylandWindow::SetPointerFocus(bool focus) {
@@ -121,10 +116,7 @@
     return;
   bounds_px_ = bounds_px;
 
-  // Opaque region is based on the size of the window. Thus, update the region
-  // on each update.
-  MaybeUpdateOpaqueRegion();
-
+  root_surface_->SetBounds(bounds_px);
   delegate_->OnBoundsChanged(bounds_px_);
 }
 
@@ -321,8 +313,8 @@
 }
 
 bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
-  wayland_surface_ = std::make_unique<WaylandSurface>(connection_, this);
-  if (!surface()) {
+  root_surface_ = std::make_unique<WaylandSurface>(connection_, this);
+  if (!root_surface_->Initialize()) {
     LOG(ERROR) << "Failed to create wl_surface";
     return false;
   }
@@ -330,13 +322,10 @@
   // Properties contain DIP bounds but the buffer scale is initially 1 so it's
   // OK to assign.  The bounds will be recalculated when the buffer scale
   // changes.
-  DCHECK_EQ(buffer_scale(), 1);
   bounds_px_ = properties.bounds;
   opacity_ = properties.opacity;
   type_ = properties.type;
 
-  AddSurfaceListener();
-
   connection_->wayland_window_manager()->AddWindow(GetWidget(), this);
 
   if (!OnInitialize(std::move(properties)))
@@ -349,29 +338,11 @@
 
   // Will do nothing for menus because they have got their scale above.
   UpdateBufferScale(false);
+  root_surface_->SetBounds(bounds_px_);
 
-  MaybeUpdateOpaqueRegion();
   return true;
 }
 
-// TODO(crbug.com/1099838): Move wl_surface calls to WaylandSurface
-void WaylandWindow::SetBufferScale(int32_t new_scale, bool update_bounds) {
-  DCHECK_GT(new_scale, 0);
-  DCHECK(wayland_surface_);
-
-  if (new_scale == buffer_scale())
-    return;
-
-  auto old_scale = buffer_scale();
-  wayland_surface_->set_buffer_scale(new_scale);
-  if (update_bounds)
-    SetBoundsDip(gfx::ScaleToRoundedRect(bounds_px_, 1.0 / old_scale));
-
-  DCHECK(surface());
-  wl_surface_set_buffer_scale(surface(), buffer_scale());
-  connection_->ScheduleFlush();
-}
-
 WaylandWindow* WaylandWindow::GetParentWindow(
     gfx::AcceleratedWidget parent_widget) {
   auto* parent_window =
@@ -398,23 +369,6 @@
   return parent_window_ ? parent_window_->GetRootParentWindow() : this;
 }
 
-// TODO(crbug.com/1099838): Move wl_surface calls to WaylandSurface
-void WaylandWindow::AddSurfaceListener() {
-  static struct wl_surface_listener surface_listener = {
-      &WaylandWindow::Enter,
-      &WaylandWindow::Leave,
-  };
-  wl_surface_add_listener(surface(), &surface_listener, nullptr);
-  wl_surface_set_user_data(surface(), this);
-}
-
-void WaylandWindow::RemoveSurfaceListener() {
-  if (surface()) {
-    wl_surface_add_listener(surface(), nullptr, nullptr);
-    wl_surface_set_user_data(surface(), nullptr);
-  }
-}
-
 void WaylandWindow::AddEnteredOutputId(struct wl_output* output) {
   // Wayland does weird things for menus so instead of tracking outputs that
   // we entered or left, we take that from the parent window and ignore this
@@ -491,19 +445,6 @@
   return child_window_ ? child_window_->GetTopMostChildWindow() : this;
 }
 
-void WaylandWindow::MaybeUpdateOpaqueRegion() {
-  if (!IsOpaqueWindow())
-    return;
-
-  wl::Object<wl_region> region(
-      wl_compositor_create_region(connection_->compositor()));
-  wl_region_add(region.get(), 0, 0, bounds_px_.width(), bounds_px_.height());
-
-  wl_surface_set_opaque_region(surface(), region.get());
-
-  connection_->ScheduleFlush();
-}
-
 bool WaylandWindow::IsOpaqueWindow() const {
   return opacity_ == ui::PlatformWindowOpacity::kOpaqueWindow;
 }
@@ -520,26 +461,10 @@
   return handled ? POST_DISPATCH_STOP_PROPAGATION : POST_DISPATCH_NONE;
 }
 
-// static
-void WaylandWindow::Enter(void* data,
-                          struct wl_surface* wl_surface,
-                          struct wl_output* output) {
-  if (auto* window = FromSurface(wl_surface))
-    window->AddEnteredOutputId(output);
-}
-
-// static
-void WaylandWindow::Leave(void* data,
-                          struct wl_surface* wl_surface,
-                          struct wl_output* output) {
-  if (auto* window = FromSurface(wl_surface))
-    window->RemoveEnteredOutputId(output);
-}
-
 std::unique_ptr<WaylandSurface> WaylandWindow::TakeWaylandSurface() {
   DCHECK(shutting_down_);
-  DCHECK(wayland_surface_);
-  return std::move(wayland_surface_);
+  DCHECK(root_surface_);
+  return std::move(root_surface_);
 }
 
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
index 937fdd6..41d3900 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -44,8 +44,6 @@
       WaylandConnection* connection,
       PlatformWindowInitProperties properties);
 
-  static WaylandWindow* FromSurface(wl_surface* surface);
-
   void OnWindowLostCapture();
 
   // Updates the surface buffer scale of the window.  Top level windows take
@@ -55,8 +53,7 @@
   // to do so (this is not needed upon window initialization).
   void UpdateBufferScale(bool update_bounds);
 
-  WaylandSurface* wayland_surface() { return wayland_surface_.get(); }
-  wl_surface* surface() const { return wayland_surface_->surface(); }
+  WaylandSurface* root_surface() const { return root_surface_.get(); }
 
   void set_parent_window(WaylandWindow* parent_window) {
     parent_window_ = parent_window;
@@ -83,7 +80,7 @@
   void set_child_window(WaylandWindow* window) { child_window_ = window; }
   WaylandWindow* child_window() const { return child_window_; }
 
-  int32_t buffer_scale() const { return wayland_surface_->buffer_scale(); }
+  int32_t buffer_scale() const { return root_surface_->buffer_scale(); }
   int32_t ui_scale() const { return ui_scale_; }
 
   const base::flat_set<uint32_t>& entered_outputs_ids() const {
@@ -157,6 +154,17 @@
   // Returns a top most child window within the same hierarchy.
   WaylandWindow* GetTopMostChildWindow();
 
+  // This should be called when a WaylandSurface part of this window becomes
+  // partially or fully within the scanout region of |output|.
+  void AddEnteredOutputId(struct wl_output* output);
+
+  // This should be called when a WaylandSurface part of this window becomes
+  // fully outside of the scanout region of |output|.
+  void RemoveEnteredOutputId(struct wl_output* output);
+
+  // Returns true iff this window is opaque.
+  bool IsOpaqueWindow() const;
+
  protected:
   WaylandWindow(PlatformWindowDelegate* delegate,
                 WaylandConnection* connection);
@@ -170,10 +178,6 @@
   // Gets a parent window for this window.
   WaylandWindow* GetParentWindow(gfx::AcceleratedWidget parent_widget);
 
-  // Sets the buffer scale.
-  void SetBufferScale(int32_t scale, bool update_bounds);
-
-  // Sets the ui scale.
   void set_ui_scale(int32_t ui_scale) { ui_scale_ = ui_scale; }
 
  private:
@@ -182,37 +186,15 @@
   // Initializes the WaylandWindow with supplied properties.
   bool Initialize(PlatformWindowInitProperties properties);
 
-  // Registers/unregisters a surface listener, so wl_output enter/leave events
-  // can be received.
-  void AddSurfaceListener();
-  void RemoveSurfaceListener();
-
-  void AddEnteredOutputId(struct wl_output* output);
-  void RemoveEnteredOutputId(struct wl_output* output);
-
   void UpdateCursorPositionFromEvent(std::unique_ptr<Event> event);
 
   WaylandWindow* GetTopLevelWindow();
 
-  // It's important to set opaque region for opaque windows (provides
-  // optimization hint for the Wayland compositor).
-  void MaybeUpdateOpaqueRegion();
-
-  bool IsOpaqueWindow() const;
-
   uint32_t DispatchEventToDelegate(const PlatformEvent& native_event);
 
   // Additional initialization of derived classes.
   virtual bool OnInitialize(PlatformWindowInitProperties properties) = 0;
 
-  // wl_surface_listener
-  static void Enter(void* data,
-                    struct wl_surface* wl_surface,
-                    struct wl_output* output);
-  static void Leave(void* data,
-                    struct wl_surface* wl_surface,
-                    struct wl_output* output);
-
   // WaylandWindowDragController might need to take ownership of the wayland
   // surface whether the window that originated the DND session gets destroyed
   // in the middle of that session (e.g: when it is snapped into a tab strip).
@@ -227,7 +209,7 @@
   WaylandWindow* parent_window_ = nullptr;
   WaylandWindow* child_window_ = nullptr;
 
-  std::unique_ptr<WaylandSurface> wayland_surface_;
+  std::unique_ptr<WaylandSurface> root_surface_;
 
   // The current cursor bitmap (immutable).
   scoped_refptr<BitmapCursorOzone> bitmap_;
diff --git a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
index 758ae1f..99eb2e701 100644
--- a/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
+++ b/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
@@ -329,7 +329,7 @@
   }
   xdg_popup_add_listener(xdg_popup_.get(), &xdg_popup_listener, this);
 
-  wl_surface_commit(wayland_window_->surface());
+  wayland_window_->root_surface()->Commit();
   return true;
 }
 
@@ -393,7 +393,7 @@
   zxdg_popup_v6_add_listener(zxdg_popup_v6_.get(), &zxdg_popup_v6_listener,
                              this);
 
-  wl_surface_commit(wayland_window_->surface());
+  wayland_window_->root_surface()->Commit();
   return true;
 }
 
diff --git a/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
index ae1ca15..cbc75a0f 100644
--- a/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
+++ b/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
@@ -267,8 +267,8 @@
   // configuration acknowledgement on each configure event.
   surface_for_popup_ = !with_toplevel;
 
-  xdg_surface_.reset(xdg_wm_base_get_xdg_surface(connection_->shell(),
-                                                 wayland_window_->surface()));
+  xdg_surface_.reset(xdg_wm_base_get_xdg_surface(
+      connection_->shell(), wayland_window_->root_surface()->surface()));
   if (!xdg_surface_) {
     LOG(ERROR) << "Failed to create xdg_surface";
     return false;
@@ -287,8 +287,7 @@
     return false;
   }
   xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this);
-  wl_surface_commit(wayland_window_->surface());
-
+  wayland_window_->root_surface()->Commit();
   connection_->ScheduleFlush();
   return true;
 }
@@ -307,7 +306,7 @@
   surface_for_popup_ = !with_toplevel;
 
   zxdg_surface_v6_.reset(zxdg_shell_v6_get_xdg_surface(
-      connection_->shell_v6(), wayland_window_->surface()));
+      connection_->shell_v6(), wayland_window_->root_surface()->surface()));
   if (!zxdg_surface_v6_) {
     LOG(ERROR) << "Failed to create zxdg_surface";
     return false;
@@ -328,8 +327,7 @@
   }
   zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(),
                                 &zxdg_toplevel_v6_listener, this);
-  wl_surface_commit(wayland_window_->surface());
-
+  wayland_window_->root_surface()->Commit();
   connection_->ScheduleFlush();
   return true;
 }
diff --git a/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc b/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
index 7b72165b4..b1c021ad3 100644
--- a/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
+++ b/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
@@ -57,7 +57,7 @@
 
 void ZWPTextInputWrapperV1::Activate(WaylandWindow* window) {
   zwp_text_input_v1_activate(obj_.get(), connection_->seat(),
-                             window->surface());
+                             window->root_surface()->surface());
 }
 
 void ZWPTextInputWrapperV1::Deactivate() {
diff --git a/ui/views/controls/table/table_view.cc b/ui/views/controls/table/table_view.cc
index fa791c47..b8071d2 100644
--- a/ui/views/controls/table/table_view.cc
+++ b/ui/views/controls/table/table_view.cc
@@ -1234,7 +1234,7 @@
       cell_data.AddIntAttribute(ax::mojom::IntAttribute::kTableCellColumnSpan,
                                 1);
       if (base::i18n::IsRTL())
-        cell_data.SetTextDirection(ax::mojom::TextDirection::kRtl);
+        cell_data.SetTextDirection(ax::mojom::WritingDirection::kRtl);
 
       auto sort_direction = ax::mojom::SortDirection::kUnsorted;
       if (column.sortable && primary_sorted_column_id.has_value() &&
@@ -1323,7 +1323,7 @@
 
       cell_data.SetName(model_->GetText(model_index, column.id));
       if (base::i18n::IsRTL())
-        cell_data.SetTextDirection(ax::mojom::TextDirection::kRtl);
+        cell_data.SetTextDirection(ax::mojom::WritingDirection::kRtl);
 
       auto sort_direction = ax::mojom::SortDirection::kUnsorted;
       if (column.sortable && primary_sorted_column_id.has_value() &&
diff --git a/ui/views/controls/tree/tree_view.cc b/ui/views/controls/tree/tree_view.cc
index 69333ebe..729d447 100644
--- a/ui/views/controls/tree/tree_view.cc
+++ b/ui/views/controls/tree/tree_view.cc
@@ -890,7 +890,7 @@
   ui::AXNodeData& node_data = ax_view->GetCustomData();
   node_data.role = ax::mojom::Role::kTreeItem;
   if (base::i18n::IsRTL())
-    node_data.SetTextDirection(ax::mojom::TextDirection::kRtl);
+    node_data.SetTextDirection(ax::mojom::WritingDirection::kRtl);
 
   base::RepeatingCallback<void(ui::AXNodeData*)> selected_callback =
       base::BindRepeating(&TreeView::PopulateAccessibilityData,