diff --git a/DEPS b/DEPS
index 64343446d..beb8ae4 100644
--- a/DEPS
+++ b/DEPS
@@ -138,11 +138,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': 'b9416caa367a770e55935916e135572c2461ca37',
+  'skia_revision': '084fa1b52f30c1b1e349b809deda5f240b90b039',
   # 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': 'eca9f8c887e111480522a0477522b0d5fdbc7095',
+  'v8_revision': 'e619ed57592ca2e2a69ab8fe2c463c810e8a7bc0',
   # 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.
@@ -150,7 +150,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '85fef1bc62f851a4de91408cfafa570dbacf544f',
+  'angle_revision': 'd187d45ede29369025595c53c7fe3ffed0688870',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -189,7 +189,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': 'd1b16325e27b766c27cc9f569c0aa334f1ecb732',
+  'freetype_revision': 'e7ac9288acde8ad21c96ad9c448ad2b2cfc9fe6a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # and whatever else without interference from each other.
@@ -269,11 +269,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'shaderc_revision': 'bd60de41e396126d7421990f00473a17a856a130',
+  'shaderc_revision': 'c6cb20db2cb35045f82a7976badc989af0469e6f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '87ab2f96d93bcf28ce97fa27a0c90f870ec040db',
+  'dawn_revision': 'df69f2482462a870adeb89fb2dd91f5acd992c1e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -297,7 +297,7 @@
   # Also, if you change these, update buildtools/DEPS too. Also update the
   # libc++ svn_revision in //buildtools/deps_revisions.gni.
   'clang_format_revision': '96636aa0e9f047f17447f2d45a094d0b59ed7917',
-  'libcxx_revision': '78822a68537b5941eb86e11a5066aa549c30998f',
+  'libcxx_revision': '5938e0582bac570a41edb3d6a2217c299adc1bc6',
   'libcxxabi_revision': '0d529660e32d77d9111912d73f2c74fc5fa2a858',
   'libunwind_revision': '69d9b84cca8354117b9fe9705a4430d789ee599b',
 }
@@ -1187,7 +1187,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '6b5210e9dfb6bbf58d62d0010e3369e95cd13085',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '91d1a33b6c734c657ffc2e318a73344bef48eb6f',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1355,7 +1355,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6f0b34abee8dba611c253738d955c59f703c147a',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'a7acc4dd8d303310fb1bd2cfafbc032f308b1fbc',
+    Var('webrtc_git') + '/src.git' + '@' + '35c26284a9e170127f39492768a74f4b93833806',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1396,7 +1396,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d96cf88529977e65f994d950bddaef85bac305f6',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@bca80c27bae8dcf30893c38b6c6a29d5190c55f0',
     'condition': 'checkout_src_internal',
   },
 
@@ -2011,7 +2011,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_ar_core',
-              'version': 'version:1.8.0-cr0',
+              'version': '4_5y1Cw_L1MHu3UedmkavqbZ7H7sYPBTdpcAOJQvlXkC',
           },
       ],
       'condition': 'checkout_android',
diff --git a/android_webview/glue/BUILD.gn b/android_webview/glue/BUILD.gn
index 217be52..a1bd319 100644
--- a/android_webview/glue/BUILD.gn
+++ b/android_webview/glue/BUILD.gn
@@ -6,19 +6,22 @@
 import("//android_webview/variables.gni")
 import("//build/config/android/config.gni")
 import("//build/config/android/rules.gni")
-import("generate_resource_rewriter.gni")
-import("glue.gni")
-
-generate_resource_rewriter("glue_resource_rewriter") {
-  # Change deps? please modify glue_library_deps variable.
-  deps = glue_library_deps
-  package_name = "com.android.webview.chromium"
-}
 
 android_library("glue") {
-  # Change deps? please modify glue_library_deps variable.
-  deps = glue_library_deps
-  srcjar_deps = [ ":glue_resource_rewriter" ]
+  deps = [
+    "//android_webview:android_webview_commandline_java",
+    "//android_webview:android_webview_java",
+    "//android_webview:android_webview_platform_services_java",
+    "//android_webview:system_webview_manifest",
+    "//android_webview/support_library/boundary_interfaces:boundary_interface_java",
+    "//android_webview/support_library/callback:callback_java",
+    "//base:base_java",
+    "//components/autofill/android:autofill_java",
+    "//components/autofill/android:provider_java",
+    "//content/public/android:content_java",
+    "//net/android:net_java",
+    "//ui/android:ui_java",
+  ]
 
   alternative_android_sdk_dep =
       "//third_party/android_sdk:public_framework_system_java"
diff --git a/android_webview/glue/generate_resource_rewriter.gni b/android_webview/glue/generate_resource_rewriter.gni
deleted file mode 100644
index 4d9a233..0000000
--- a/android_webview/glue/generate_resource_rewriter.gni
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/android/rules.gni")
-
-# Generate ResourceRewriter.java from Android Libraries according the dep
-# graph.
-# Argument:
-#   deps
-#     The same deps of target that uses the generated ResourceRewriter.
-#   package_name
-#     The package name of ResourceRewriter.java.
-#
-# This target generates a single srcjar containing generated
-# ResourceRewrite.java which will list the R classes generated by all the
-# Android libraries reachabled from the target specified in deps. Add this
-# target to srcjar_deps of android_library will call  ResourceRewriter.
-#
-template("generate_resource_rewriter") {
-  set_sources_assignment_filter([])
-  assert(defined(invoker.package_name))
-
-  _final_target_name = target_name
-  _build_config = "$target_gen_dir/${target_name}.build_config"
-  _build_config_target_name = "$target_name$build_config_target_suffix"
-  _srcjar = "$target_gen_dir/${target_name}.srcjar"
-  write_build_config(_build_config_target_name) {
-    possible_config_deps = invoker.deps
-    type = "resource_rewriter"
-    build_config = _build_config
-  }
-
-  action(_final_target_name) {
-    forward_variables_from(invoker, [ "visibility" ])
-    inputs = [
-      _build_config,
-    ]
-    deps = invoker.deps + [ ":${_build_config_target_name}" ]
-    script = "//build/android/gyp/generate_resource_rewriter.py"
-
-    _rebased_build_config = rebase_path(_build_config, root_build_dir)
-    args = [
-      "--package-name",
-      invoker.package_name,
-      "--dep-packages",
-      "@FileArg($_rebased_build_config:resources:extra_package_names)",
-      "--srcjar",
-      rebase_path(_srcjar, root_build_dir),
-    ]
-    outputs = [
-      _srcjar,
-    ]
-  }
-}
diff --git a/android_webview/glue/glue.gni b/android_webview/glue/glue.gni
deleted file mode 100644
index 0581c9bb..0000000
--- a/android_webview/glue/glue.gni
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This variable shared between 'glue' and 'glue_resource_rewriter' because
-# ResourceRewrite.java need to be generated according 'glue' deps.
-glue_library_deps = [
-  "//android_webview:android_webview_java",
-  "//android_webview:android_webview_commandline_java",
-  "//android_webview:android_webview_platform_services_java",
-  "//android_webview:system_webview_manifest",
-  "//android_webview/support_library/boundary_interfaces:boundary_interface_java",
-  "//android_webview/support_library/callback:callback_java",
-  "//base:base_java",
-  "//components/autofill/android:autofill_java",
-  "//components/autofill/android:provider_java",
-  "//content/public/android:content_java",
-  "//net/android:net_java",
-  "//ui/android:ui_java",
-]
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java
index 1d286e2..acca205 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java
@@ -32,6 +32,7 @@
 import org.chromium.android_webview.AwServiceWorkerController;
 import org.chromium.android_webview.AwTracingController;
 import org.chromium.android_webview.HttpAuthDatabase;
+import org.chromium.android_webview.R;
 import org.chromium.android_webview.ScopedSysTraceEvent;
 import org.chromium.android_webview.VariationsSeedLoader;
 import org.chromium.android_webview.WebViewChromiumRunQueue;
@@ -248,7 +249,8 @@
                 packageName = webViewPackageInfo.applicationInfo.metaData.getString(
                         "com.android.webview.WebViewDonorPackage", packageName);
             }
-            ResourceRewriter.rewriteRValues(mFactory.getWebViewDelegate().getPackageId(
+
+            R.onResourcesLoaded(mFactory.getWebViewDelegate().getPackageId(
                     context.getResources(), packageName));
 
             AwResource.setResources(context.getResources());
diff --git a/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/DropDownListTest.java b/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/DropDownListTest.java
index 84e7cb88..51611e0 100644
--- a/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/DropDownListTest.java
+++ b/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/DropDownListTest.java
@@ -18,6 +18,7 @@
 import static org.junit.Assert.assertEquals;
 
 import android.graphics.Point;
+import android.os.Build;
 import android.support.test.espresso.web.sugar.Web;
 import android.support.test.espresso.web.webdriver.Locator;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -85,11 +86,14 @@
      * Test Drop Down List works in ViewPort Scale Factor > 1 in wideViewPortMode
      */
     // TODO(aluo): Re-enable once crbug.com/947352 is fixed.
-    @DisableIf.Build(product_name_includes = "walleye")
+    @DisableIf.
+    Build(message = "crbug.com/947352", sdk_is_greater_than = Build.VERSION_CODES.LOLLIPOP,
+            sdk_is_less_than = Build.VERSION_CODES.P)
     @Test
     @SmallTest
     @UseLayout("edittext_webview")
-    public void testDropDownScaledViewPortUseWideViewPort() {
+    public void
+    testDropDownScaledViewPortUseWideViewPort() {
         onView(withId(R.id.webview)).perform(Actions.setUseWideViewPort());
         mWebViewActivityRule.loadFileSync(HTML_SCALED, false);
         WebView webView = (WebView) mWebViewActivityRule.getActivity()
diff --git a/ash/custom_tab/arc_custom_tab_view.cc b/ash/custom_tab/arc_custom_tab_view.cc
index 52ea32a8..bb096efdfd 100644
--- a/ash/custom_tab/arc_custom_tab_view.cc
+++ b/ash/custom_tab/arc_custom_tab_view.cc
@@ -8,8 +8,6 @@
 #include <string>
 #include <utility>
 
-#include "ash/shell.h"
-#include "components/exo/shell_surface_util.h"
 #include "components/exo/surface.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_targeter.h"
@@ -22,21 +20,6 @@
 
 namespace {
 
-// Tries to find the specified ARC window recursively.
-aura::Window* FindArcWindow(const aura::Window::Windows& windows,
-                            const std::string& arc_app_id) {
-  for (aura::Window* window : windows) {
-    const std::string* id = exo::GetShellApplicationId(window);
-    if (id && *id == arc_app_id)
-      return window;
-
-    aura::Window* result = FindArcWindow(window->children(), arc_app_id);
-    if (result)
-      return result;
-  }
-  return nullptr;
-}
-
 // Enumerates surfaces under the window.
 void EnumerateSurfaces(aura::Window* window, std::vector<exo::Surface*>* out) {
   auto* surface = exo::Surface::AsSurface(window);
@@ -52,17 +35,9 @@
 ArcCustomTab::~ArcCustomTab() = default;
 
 // static
-std::unique_ptr<ArcCustomTab> ArcCustomTab::Create(int32_t task_id,
+std::unique_ptr<ArcCustomTab> ArcCustomTab::Create(aura::Window* arc_app_window,
                                                    int32_t surface_id,
                                                    int32_t top_margin) {
-  const std::string arc_app_id =
-      base::StringPrintf("org.chromium.arc.%d", task_id);
-  aura::Window* arc_app_window =
-      FindArcWindow(ash::Shell::Get()->GetAllRootWindows(), arc_app_id);
-  if (!arc_app_window) {
-    LOG(ERROR) << "No ARC window with the specified task ID " << task_id;
-    return nullptr;
-  }
   views::Widget* widget =
       views::Widget::GetWidgetForNativeWindow(arc_app_window);
   if (!widget) {
diff --git a/ash/public/cpp/arc_custom_tab.h b/ash/public/cpp/arc_custom_tab.h
index 2121174..0bab988 100644
--- a/ash/public/cpp/arc_custom_tab.h
+++ b/ash/public/cpp/arc_custom_tab.h
@@ -18,7 +18,7 @@
  public:
   // Creates a new ArcCustomTab instance. Returns null when the arguments are
   // invalid.
-  static std::unique_ptr<ArcCustomTab> Create(int32_t task_id,
+  static std::unique_ptr<ArcCustomTab> Create(aura::Window* arc_app_window,
                                               int32_t surface_id,
                                               int32_t top_margin);
 
diff --git a/ash/wm/window_resizer.cc b/ash/wm/window_resizer.cc
index 026d19f..c9ea3c8 100644
--- a/ash/wm/window_resizer.cc
+++ b/ash/wm/window_resizer.cc
@@ -85,10 +85,7 @@
   DCHECK(window_state_->drag_details());
 }
 
-WindowResizer::~WindowResizer() {
-  if (destroyed_)
-    *destroyed_ = true;
-}
+WindowResizer::~WindowResizer() = default;
 
 // static
 int WindowResizer::GetBoundsChangeForWindowComponent(int component) {
@@ -272,20 +269,14 @@
 void WindowResizer::SetBoundsDuringResize(const gfx::Rect& bounds) {
   aura::Window* window = GetTarget();
   DCHECK(window);
-  bool destroyed = false;
-  destroyed_ = &destroyed;
-  aura::WindowTracker tracker;
-  tracker.Add(window);
-
   const gfx::Rect original_bounds = window->bounds();
   window->SetBounds(bounds);
-
+  aura::WindowTracker tracker;
+  tracker.Add(window);
   if (tracker.windows().empty())
     return;  // Assume we've been destroyed.
   if (bounds.size() == original_bounds.size())
     return;
-  CHECK(!destroyed);
-  destroyed_ = nullptr;
   recorder_->RequestNext();
 }
 
diff --git a/ash/wm/window_resizer.h b/ash/wm/window_resizer.h
index 6545519..35e9899 100644
--- a/ash/wm/window_resizer.h
+++ b/ash/wm/window_resizer.h
@@ -110,8 +110,6 @@
   // Updates |new_bounds| to adhere to the aspect ratio.
   void CalculateBoundsWithAspectRatio(float aspect_ratio,
                                       gfx::Rect* new_bounds);
-  // Remove once it is confirmed that crbug.com/970911 is fixed.
-  bool* destroyed_ = nullptr;
 
   std::unique_ptr<PresentationTimeRecorder> recorder_;
 
diff --git a/base/android/java/src/org/chromium/base/SysUtils.java b/base/android/java/src/org/chromium/base/SysUtils.java
index d4eb30d..a5accb6c 100644
--- a/base/android/java/src/org/chromium/base/SysUtils.java
+++ b/base/android/java/src/org/chromium/base/SysUtils.java
@@ -9,6 +9,8 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Build;
+import android.os.Environment;
+import android.os.StatFs;
 import android.os.StrictMode;
 import android.util.Log;
 
@@ -29,12 +31,18 @@
     // A device reporting strictly more total memory in megabytes cannot be considered 'low-end'.
     private static final int ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB = 512;
     private static final int ANDROID_O_LOW_MEMORY_DEVICE_THRESHOLD_MB = 1024;
+    private static final int BYTES_PER_GIGABYTE = 1024 * 1024 * 1024;
+
+    // A device reporting more disk capacity in gigabytes than this is considered high end.
+    private static final long HIGH_END_DEVICE_DISK_CAPACITY_GB = 24;
 
     private static final String TAG = "SysUtils";
 
     private static Boolean sLowEndDevice;
     private static Integer sAmountOfPhysicalMemoryKB;
 
+    private static Boolean sHighEndDiskDevice;
+
     private static CachedMetrics.BooleanHistogramSample sLowEndMatches =
             new CachedMetrics.BooleanHistogramSample("Android.SysUtilsLowEndMatches");
 
@@ -196,4 +204,26 @@
     }
 
     private static native void nativeLogPageFaultCountToTracing();
+
+    /**
+     * @return Whether or not this device should be considered a high end device from a disk
+     *         capacity point of view.
+     */
+    public static boolean isHighEndDiskDevice() {
+        if (sHighEndDiskDevice == null) {
+            sHighEndDiskDevice = detectHighEndDiskDevice();
+        }
+        return sHighEndDiskDevice.booleanValue();
+    }
+
+    private static boolean detectHighEndDiskDevice() {
+        try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
+            StatFs dataStats = new StatFs(Environment.getDataDirectory().getAbsolutePath());
+            long totalGBytes = dataStats.getTotalBytes() / BYTES_PER_GIGABYTE;
+            return totalGBytes >= HIGH_END_DEVICE_DISK_CAPACITY_GB;
+        } catch (IllegalArgumentException e) {
+            Log.v(TAG, "Cannot get disk data capacity", e);
+        }
+        return false;
+    }
 }
diff --git a/base/stl_util.h b/base/stl_util.h
index 8d872507..e22b029 100644
--- a/base/stl_util.h
+++ b/base/stl_util.h
@@ -230,12 +230,22 @@
   return c.erase(it, it);
 }
 
-// Explicit overload for std::forward_list where erase() is spelt erase_after().
+// Explicit overload for std::forward_list where erase() is named erase_after().
 template <typename T, typename Allocator>
 constexpr auto ConstCastIterator(
     std::forward_list<T, Allocator>& c,
     typename std::forward_list<T, Allocator>::const_iterator it) {
+// The erase_after(it, it) trick used below does not work for libstdc++ [1],
+// thus we need a different way.
+// TODO(crbug.com/972541): Remove this workaround once libstdc++ is fixed on all
+// platforms.
+//
+// [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90857
+#if defined(__GLIBCXX__)
+  return c.insert_after(it, {});
+#else
   return c.erase_after(it, it);
+#endif
 }
 
 // Specialized O(1) const casting for random access iterators. This is
diff --git a/base/stl_util_unittest.cc b/base/stl_util_unittest.cc
index 8c96913..ab3fdb9 100644
--- a/base/stl_util_unittest.cc
+++ b/base/stl_util_unittest.cc
@@ -105,6 +105,9 @@
                              decltype(it)>::value,
                 "it is not a iterator.");
   EXPECT_EQ(c_it, it);
+  // Const casting the iterator should not modify the underlying container.
+  Container other = {1, 2, 3, 4, 5};
+  EXPECT_THAT(c, testing::ContainerEq(other));
 }
 
 struct CustomIntHash {
@@ -308,7 +311,6 @@
   RunConstCastIteratorTest<std::deque<int>>();
   RunConstCastIteratorTest<std::vector<int>>();
   RunConstCastIteratorTest<std::array<int, 5>>();
-  RunConstCastIteratorTest<std::initializer_list<int>>();
   RunConstCastIteratorTest<int[5]>();
 
   // Associative Containers
diff --git a/base/util/type_safety/BUILD.gn b/base/util/type_safety/BUILD.gn
index 011e577..a335cc22 100644
--- a/base/util/type_safety/BUILD.gn
+++ b/base/util/type_safety/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/jumbo.gni")
+import("//build/nocompile.gni")
 
 # Change this target's type to jumbo_component if it starts to contain more than
 # just headers. Header-only targets cannot be compiled to libraries, so it must
@@ -10,6 +11,7 @@
 source_set("type_safety") {
   sources = [
     "id_type.h",
+    "pass_key.h",
     "strong_alias.h",
   ]
 }
@@ -18,6 +20,7 @@
   testonly = true
   sources = [
     "id_type_unittest.cc",
+    "pass_key_unittest.cc",
     "strong_alias_unittest.cc",
   ]
 
@@ -26,3 +29,18 @@
     "//testing/gtest",
   ]
 }
+
+if (enable_nocompile_tests) {
+  nocompile_test("type_safety_nocompile_tests") {
+    sources = [
+      "pass_key_unittest.nc",
+    ]
+
+    deps = [
+      ":type_safety",
+      "//base:base_unittests_tasktraits",
+      "//base/test:run_all_unittests",
+      "//testing/gtest",
+    ]
+  }
+}
diff --git a/base/util/type_safety/pass_key.h b/base/util/type_safety/pass_key.h
new file mode 100644
index 0000000..987822ed
--- /dev/null
+++ b/base/util/type_safety/pass_key.h
@@ -0,0 +1,48 @@
+// 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 BASE_UTIL_TYPE_SAFETY_PASS_KEY_H_
+#define BASE_UTIL_TYPE_SAFETY_PASS_KEY_H_
+
+namespace util {
+
+// util::PassKey can be used to restrict access to functions to an authorized
+// caller. The primary use case is restricting the construction of an object in
+// situations where the constructor needs to be public, which may be the case
+// if the object must be constructed through a helper function, such as
+// blink::MakeGarbageCollected.
+//
+// For example, to limit the creation of 'Foo' to the 'Manager' class:
+//
+//  class Foo {
+//   public:
+//    Foo(util::PassKey<Manager>);
+//  };
+//
+//  class Manager {
+//   public:
+//    using PassKey = util::PassKey<Manager>;
+//    Manager() : foo_(blink::MakeGarbageCollected<Foo>(PassKey())) {}
+//    void Trace(blink::Visitor* visitor) { visitor->Trace(foo_); }
+//    Foo* GetFooSingleton() { foo_; }
+//
+//   private:
+//    blink::Member<Foo> foo_;
+//  };
+//
+// In the above example, the 'Foo' constructor requires an instance of
+// util::PassKey<Manager>. Only Manager is allowed to create such instances,
+// making the constructor unusable elsewhere.
+template <typename T>
+class PassKey {
+ private:
+  // Avoid =default to disallow creation by uniform initialization.
+  PassKey() {}
+
+  friend T;
+};
+
+}  // namespace util
+
+#endif  // BASE_UTIL_TYPE_SAFETY_PASS_KEY_H_
diff --git a/base/util/type_safety/pass_key_unittest.cc b/base/util/type_safety/pass_key_unittest.cc
new file mode 100644
index 0000000..51431b4
--- /dev/null
+++ b/base/util/type_safety/pass_key_unittest.cc
@@ -0,0 +1,46 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/util/type_safety/pass_key.h"
+
+#include <utility>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace util {
+namespace {
+
+class Manager;
+
+// May not be created without a PassKey.
+class Restricted {
+ public:
+  Restricted(util::PassKey<Manager>) {}
+};
+
+class Manager {
+ public:
+  enum class ExplicitConstruction { kTag };
+  enum class UniformInitialization { kTag };
+
+  Manager(ExplicitConstruction) : restricted_(util::PassKey<Manager>()) {}
+  Manager(UniformInitialization) : restricted_({}) {}
+
+ private:
+  Restricted restricted_;
+};
+
+// If this file compiles, then these test will run and pass. This is useful
+// for verifying that the file actually was compiled into the unit test binary.
+
+TEST(PassKeyTest, ExplicitConstruction) {
+  Manager manager(Manager::ExplicitConstruction::kTag);
+}
+
+TEST(PassKeyTest, UniformInitialization) {
+  Manager manager(Manager::UniformInitialization::kTag);
+}
+
+}  // namespace
+}  // namespace util
diff --git a/base/util/type_safety/pass_key_unittest.nc b/base/util/type_safety/pass_key_unittest.nc
new file mode 100644
index 0000000..f8a2985
--- /dev/null
+++ b/base/util/type_safety/pass_key_unittest.nc
@@ -0,0 +1,73 @@
+// 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.
+
+// This is a no-compile test suite.
+// http://dev.chromium.org/developers/testing/no-compile-tests
+
+#include "base/util/type_safety/pass_key.h"
+
+namespace util {
+
+class Manager;
+
+// May not be created without a PassKey.
+class Restricted {
+ public:
+  Restricted(util::PassKey<Manager>) {}
+};
+
+int Secret(util::PassKey<Manager>) {
+  return 1;
+}
+
+#if defined(NCTEST_UNAUTHORIZED_PASS_KEY_IN_INITIALIZER)  // [r"fatal error: calling a private constructor of class 'util::PassKey<util::Manager>'"]
+
+class NotAManager {
+ public:
+  NotAManager() : restricted_(util::PassKey<Manager>()) {}
+
+ private:
+  Restricted restricted_;
+};
+
+void WillNotCompile() {
+  NotAManager not_a_manager;
+}
+
+#elif defined(NCTEST_UNAUTHORIZED_UNIFORM_INITIALIZED_PASS_KEY_IN_INITIALIZER)  // [r"fatal error: calling a private constructor of class 'util::PassKey<util::Manager>'"]
+
+class NotAManager {
+ public:
+  NotAManager() : restricted_({}) {}
+
+ private:
+  Restricted restricted_;
+};
+
+void WillNotCompile() {
+  NotAManager not_a_manager;
+}
+
+#elif defined(NCTEST_UNAUTHORIZED_PASS_KEY_IN_FUNCTION)  // [r"fatal error: calling a private constructor of class 'util::PassKey<util::Manager>'"]
+
+int WillNotCompile() {
+  return Secret(util::PassKey<Manager>());
+}
+
+#elif defined(NCTEST_UNAUTHORIZED_UNIFORM_INITIALIZATION_WITH_DEDUCED_PASS_KEY_TYPE)  // [r"fatal error: calling a private constructor of class 'util::PassKey<util::Manager>'"]
+
+int WillNotCompile() {
+  return Secret({});
+}
+
+#elif defined(NCTEST_UNAUTHORIZED_UNIFORM_INITIALIZATION)  // [r"fatal error: calling a private constructor of class 'util::PassKey<util::Manager>'"]
+
+int WillNotCompile() {
+  util::PassKey<Manager> key {};
+  return Secret(key);
+}
+
+#endif
+
+}  // namespace util
diff --git a/build/android/gyp/OWNERS b/build/android/gyp/OWNERS
index 74dca6f..273c114 100644
--- a/build/android/gyp/OWNERS
+++ b/build/android/gyp/OWNERS
@@ -1,6 +1,7 @@
 agrieve@chromium.org
 estevenson@chromium.org
 digit@chromium.org
+smaier@chromium.org
 wnwen@chromium.org
 
 # COMPONENT: Build
diff --git a/build/android/gyp/compile_resources.py b/build/android/gyp/compile_resources.py
index 8a85588b..5ab30e6e 100755
--- a/build/android/gyp/compile_resources.py
+++ b/build/android/gyp/compile_resources.py
@@ -894,9 +894,28 @@
       rjava_build_options.ExportAllResources()
       rjava_build_options.GenerateOnResourcesLoaded()
 
+    custom_root_package_name = None
+    grandparent_custom_package_name = None
+
+    if options.arsc_package_name:
+      # This is for test apks with an apk under test. If we have an apk under
+      # test we don't want to name the resources for both the test apk and the
+      # under test apk "base". This special case lets us name the test apk's
+      # resources "test".
+      custom_root_package_name = 'test'
+    elif options.package_name:
+      # If there exists a custom package name such as vr for a feature module,
+      # pass the name and base for the parent_custom_root_package_name.
+      custom_root_package_name = options.package_name
+      grandparent_custom_package_name = 'base'
+    else:
+      # No grandparent_custom_package_name for base module
+      custom_root_package_name = 'base'
+
     resource_utils.CreateRJavaFiles(
         build.srcjar_dir, None, build.r_txt_path, options.extra_res_packages,
-        options.extra_r_text_files, rjava_build_options, options.srcjar_out)
+        options.extra_r_text_files, rjava_build_options, options.srcjar_out,
+        custom_root_package_name, grandparent_custom_package_name)
 
     build_utils.ZipDir(build.srcjar_path, build.srcjar_dir)
 
diff --git a/build/android/gyp/generate_resource_rewriter.py b/build/android/gyp/generate_resource_rewriter.py
deleted file mode 100755
index ba635a29..0000000
--- a/build/android/gyp/generate_resource_rewriter.py
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Generate ResourceRewriter.java which overwrites the given package's
-   resource id.
-"""
-
-import argparse
-import os
-import sys
-import zipfile
-
-from util import build_utils
-
-# Import jinja2 from third_party/jinja2
-sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),
-                                             '..',
-                                             '..',
-                                             '..',
-                                             'third_party')))
-import jinja2
-
-
-RESOURCE_REWRITER_JAVA="ResourceRewriter.java"
-
-RESOURCE_REWRITER="""/* AUTO-GENERATED FILE.  DO NOT MODIFY. */
-
-package {{ package }};
-/**
- * Helper class used to fix up resource ids.
- */
-class ResourceRewriter {
-    /**
-     * Rewrite the R 'constants' for the WebView.
-     */
-    public static void rewriteRValues(final int packageId) {
-        {% for res_package in res_packages %}
-        {{ res_package }}.R.onResourcesLoaded(packageId);
-        {% endfor %}
-    }
-}
-"""
-
-def ParseArgs(args):
-  """Parses command line options.
-
-  Returns:
-    An Namespace from argparse.parse_args()
-  """
-  parser = argparse.ArgumentParser(prog='generate_resource_rewriter')
-
-  parser.add_argument('--package-name',
-                      required=True,
-                      help='The package name of ResourceRewriter.')
-  parser.add_argument('--dep-packages',
-                      required=True,
-                      help='A list of packages whose resource id will be'
-                           'overwritten in ResourceRewriter.')
-  parser.add_argument('--output-dir',
-                      help='A output directory of generated'
-                           ' ResourceRewriter.java')
-  parser.add_argument('--srcjar',
-                      help='The path of generated srcjar which has'
-                           ' ResourceRewriter.java')
-
-  return parser.parse_args(args)
-
-
-def CreateResourceRewriter(package, res_packages, output_dir):
-  build_utils.MakeDirectory(output_dir)
-  java_path = os.path.join(output_dir, RESOURCE_REWRITER_JAVA)
-  template = jinja2.Template(RESOURCE_REWRITER,
-                             trim_blocks=True,
-                             lstrip_blocks=True)
-  output = template.render(package=package, res_packages=res_packages)
-  with open(java_path, 'w') as f:
-    f.write(output)
-
-def CreateResourceRewriterSrcjar(package, res_packages, srcjar_path):
-  with build_utils.TempDir() as temp_dir:
-    output_dir = os.path.join(temp_dir, *package.split('.'))
-    CreateResourceRewriter(package, res_packages, output_dir)
-    build_utils.DoZip([os.path.join(output_dir, RESOURCE_REWRITER_JAVA)],
-                      srcjar_path,
-                      temp_dir)
-
-
-def main():
-  options = ParseArgs(build_utils.ExpandFileArgs(sys.argv[1:]))
-  package = options.package_name
-  if options.output_dir:
-    output_dir = os.path.join(options.output_dir, *package.split('.'))
-    CreateResourceRewriter(
-        package,
-        build_utils.ParseGnList(options.dep_packages),
-        output_dir)
-  else:
-    CreateResourceRewriterSrcjar(
-        package,
-        build_utils.ParseGnList(options.dep_packages),
-        options.srcjar)
-
-  return 0
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/build/android/gyp/prepare_resources.py b/build/android/gyp/prepare_resources.py
index cec2327..4f5ab17 100755
--- a/build/android/gyp/prepare_resources.py
+++ b/build/android/gyp/prepare_resources.py
@@ -224,6 +224,8 @@
         if options.shared_resources:
           rjava_build_options.GenerateOnResourcesLoaded()
 
+        # Not passing in custom_root_package_name or parent to keep
+        # file names unique.
         resource_utils.CreateRJavaFiles(
             build.srcjar_dir, package, r_txt_path, options.extra_res_packages,
             options.extra_r_text_files, rjava_build_options, options.srcjar_out)
diff --git a/build/android/gyp/util/resource_utils.py b/build/android/gyp/util/resource_utils.py
index 9af4442..c356994 100644
--- a/build/android/gyp/util/resource_utils.py
+++ b/build/android/gyp/util/resource_utils.py
@@ -328,13 +328,21 @@
       return entry.name not in self.resources_whitelist
 
 
-def CreateRJavaFiles(srcjar_dir, package, main_r_txt_file, extra_res_packages,
-                     extra_r_txt_files, rjava_build_options, srcjar_out):
+def CreateRJavaFiles(srcjar_dir,
+                     package,
+                     main_r_txt_file,
+                     extra_res_packages,
+                     extra_r_txt_files,
+                     rjava_build_options,
+                     srcjar_out,
+                     custom_root_package_name=None,
+                     grandparent_custom_package_name=None):
   """Create all R.java files for a set of packages and R.txt files.
 
   Args:
     srcjar_dir: The top-level output directory for the generated files.
-    package: Top-level package name.
+    package: Package name for R java source files which will inherit
+      from the root R java file.
     main_r_txt_file: The main R.txt file containing the valid values
       of _all_ resource IDs.
     extra_res_packages: A list of extra package names.
@@ -344,6 +352,13 @@
     rjava_build_options: An RJavaBuildOptions instance that controls how
       exactly the R.java file is generated.
     srcjar_out: Path of desired output srcjar.
+    custom_root_package_name: Custom package name for module root R.java file,
+      (eg. vr for gen.vr package).
+    grandparent_custom_package_name: Custom root package name for the root
+      R.java file to inherit from. DFM root R.java files will have "base"
+      as the grandparent_custom_package_name. The format of this package name
+      is identical to custom_root_package_name.
+      (eg. for vr grandparent_custom_package_name would be "base")
   Raises:
     Exception if a package name appears several times in |extra_res_packages|
   """
@@ -367,18 +382,20 @@
     all_resources[(entry.resource_type, entry.name)] = entry
     all_resources_by_type[entry.resource_type].append(entry)
 
-  # Creating the root R.java file. We use srcjar_out to provide unique package
-  # names, since when one java target depends on 2 different targets (each with
-  # resources), those 2 root resource packages have to be different from one
-  # another. We add an underscore before each subdirectory so that if a reserved
-  # keyword (for example, "public") is used as a directory name, it will not
-  # cause Java to complain.
-  root_r_java_package = re.sub('[^\w\.]', '', srcjar_out.replace('/', '._'))
+  if custom_root_package_name:
+    # Custom package name is available, thus use it for root_r_java_package.
+    root_r_java_package = GetCustomPackagePath(custom_root_package_name)
+  else:
+    # Create a unique name using srcjar_out. Underscores are added to ensure
+    # no reserved keywords are used for directory names.
+    root_r_java_package = re.sub('[^\w\.]', '', srcjar_out.replace('/', '._'))
+
   root_r_java_dir = os.path.join(srcjar_dir, *root_r_java_package.split('.'))
   build_utils.MakeDirectory(root_r_java_dir)
   root_r_java_path = os.path.join(root_r_java_dir, 'R.java')
   root_java_file_contents = _RenderRootRJavaSource(
-      root_r_java_package, all_resources_by_type, rjava_build_options)
+      root_r_java_package, all_resources_by_type, rjava_build_options,
+      grandparent_custom_package_name)
   with open(root_r_java_path, 'w') as f:
     f.write(root_java_file_contents)
 
@@ -479,7 +496,12 @@
       has_on_resources_loaded=rjava_build_options.has_on_resources_loaded)
 
 
-def _RenderRootRJavaSource(package, all_resources_by_type, rjava_build_options):
+def GetCustomPackagePath(package_name):
+  return 'gen.' + package_name + '_module'
+
+
+def _RenderRootRJavaSource(package, all_resources_by_type, rjava_build_options,
+                           grandparent_custom_package_name):
   """Render an R.java source file. See _CreateRJaveSourceFile for args info."""
   final_resources_by_type = collections.defaultdict(list)
   non_final_resources_by_type = collections.defaultdict(list)
@@ -497,13 +519,19 @@
   create_id = ('{{ e.resource_type }}.{{ e.name }} ^= packageIdTransform;')
   create_id_arr = ('{{ e.resource_type }}.{{ e.name }}[i] ^='
                    ' packageIdTransform;')
-  for_loop_condition  = ('int i = {{ startIndex(e) }}; i < '
-                         '{{ e.resource_type }}.{{ e.name }}.length; ++i')
+  for_loop_condition = ('int i = {{ startIndex(e) }}; i < '
+                        '{{ e.resource_type }}.{{ e.name }}.length; ++i')
 
   # Here we diverge from what aapt does. Because we have so many
   # resources, the onResourcesLoaded method was exceeding the 64KB limit that
   # Java imposes. For this reason we split onResourcesLoaded into different
   # methods for each resource type.
+  extends_string = ''
+  dep_path = ''
+  if grandparent_custom_package_name:
+    extends_string = 'extends {{ parent_path }}.R.{{ resource_type }} '
+    dep_path = GetCustomPackagePath(grandparent_custom_package_name)
+
   template = Template(
       """/* AUTO-GENERATED FILE.  DO NOT MODIFY. */
 
@@ -511,7 +539,7 @@
 
 public final class R {
     {% for resource_type in resource_types %}
-    public static class {{ resource_type }} {
+    public static class {{ resource_type }} """ + extends_string + """ {
         {% for e in final_resources[resource_type] %}
         public static final {{ e.java_type }} {{ e.name }} = {{ e.value }};
         {% endfor %}
@@ -558,14 +586,14 @@
 """,
       trim_blocks=True,
       lstrip_blocks=True)
-
   return template.render(
       package=package,
       resource_types=sorted(all_resources_by_type),
       has_on_resources_loaded=rjava_build_options.has_on_resources_loaded,
       final_resources=final_resources_by_type,
       non_final_resources=non_final_resources_by_type,
-      startIndex=_GetNonSystemIndex)
+      startIndex=_GetNonSystemIndex,
+      parent_path=dep_path)
 
 
 def ExtractPackageFromManifest(manifest_path):
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index 2c961732..845fcd6 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -1372,6 +1372,13 @@
     javac_full_classpath = [
         c['unprocessed_jar_path'] for c in all_library_deps]
 
+    # Adding base module to classpath to compile against its R.java file
+    if base_module_build_config:
+      javac_full_classpath.append(
+          base_module_build_config['deps_info']['jar_path'])
+      javac_full_interface_classpath.append(
+          base_module_build_config['deps_info']['interface_jar_path'])
+
     for dep in direct_group_deps:
       javac_classpath.extend(dep.get('extra_classpath_jars', []))
       javac_interface_classpath.extend(
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 76cae75..1c22933 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2032,7 +2032,6 @@
   #     target.
   template("android_apk_or_module") {
     forward_variables_from(invoker, [ "testonly" ])
-
     assert(defined(invoker.final_apk_path) || defined(invoker.name))
     assert(defined(invoker.android_manifest))
     _gen_dir = "$target_gen_dir/$target_name"
@@ -2640,6 +2639,18 @@
     }
 
     _java_target = "${_template_name}__java"
+
+    # Included special group to bypass looking for __java__build_config file
+    # for base module. Build config for base_module does not include the __java
+    # (eg. monochrome_public_bundle__base_bundle_module__build_config)
+    # and thus, this workaround skips looking for one.
+    if (defined(invoker.base_module_target)) {
+      group("${_template_name}__group") {
+        deps = [
+          "${invoker.base_module_target}__java",
+        ]
+      }
+    }
     java_library_impl(_java_target) {
       forward_variables_from(invoker,
                              [
@@ -2665,6 +2676,12 @@
         type = "android_app_bundle_module"
         res_size_info_path = _res_size_info_path
         is_base_module = _is_base_module
+
+        if (!is_base_module) {
+          if (defined(invoker.base_module_target)) {
+            _deps += [ ":${_template_name}__group" ]
+          }
+        }
       } else {
         type = "android_apk"
       }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 65310178..e2d8967 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8910830672247271936
\ No newline at end of file
+8910771380915113792
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index a4ba380..50d977f 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8910834325322396848
\ No newline at end of file
+8910773990085370640
\ No newline at end of file
diff --git a/buildtools/DEPS b/buildtools/DEPS
index b64e364..4b944b9 100644
--- a/buildtools/DEPS
+++ b/buildtools/DEPS
@@ -18,7 +18,7 @@
 
   # When changing these, also update the svn revisions in deps_revisions.gni
   'clang_format_revision': '96636aa0e9f047f17447f2d45a094d0b59ed7917',
-  'libcxx_revision':       '78822a68537b5941eb86e11a5066aa549c30998f',
+  'libcxx_revision':       '5938e0582bac570a41edb3d6a2217c299adc1bc6',
   'libcxxabi_revision':    '0d529660e32d77d9111912d73f2c74fc5fa2a858',
   'libunwind_revision':    '69d9b84cca8354117b9fe9705a4430d789ee599b',
 }
diff --git a/buildtools/deps_revisions.gni b/buildtools/deps_revisions.gni
index e7c365e..7fb5baa3 100644
--- a/buildtools/deps_revisions.gni
+++ b/buildtools/deps_revisions.gni
@@ -5,5 +5,5 @@
 declare_args() {
   # The libc++ svn revision that belongs to the git hash in DEPS. Used to cause
   # full rebuilds on libc++ rolls.
-  libcxx_svn_revision = "363117"
+  libcxx_svn_revision = "361348"
 }
diff --git a/buildtools/third_party/libc++/BUILD.gn b/buildtools/third_party/libc++/BUILD.gn
index f5b0890f..a021562 100644
--- a/buildtools/third_party/libc++/BUILD.gn
+++ b/buildtools/third_party/libc++/BUILD.gn
@@ -55,7 +55,6 @@
     "trunk/src/algorithm.cpp",
     "trunk/src/any.cpp",
     "trunk/src/bind.cpp",
-    "trunk/src/charconv.cpp",
     "trunk/src/chrono.cpp",
     "trunk/src/condition_variable.cpp",
     "trunk/src/debug.cpp",
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 69e6754..6992681 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -320,6 +320,7 @@
     "//components/payments/mojom:mojom_java",
     "//components/policy/android:policy_java",
     "//components/safe_browsing/android:safe_browsing_java",
+    "//components/search_engines/android:java",
     "//components/signin/core/browser/android:java",
     "//components/spellcheck/browser/android:java",
     "//components/sync/android:sync_java",
@@ -804,6 +805,7 @@
     "//components/policy/android:policy_java",
     "//components/policy/android:policy_java_test_support",
     "//components/safe_browsing/android:safe_browsing_java",
+    "//components/search_engines/android:java",
     "//components/signin/core/browser/android:java",
     "//components/signin/core/browser/android:signin_java_test_support",
     "//components/signin/core/browser/android:signin_javatests",
@@ -2563,8 +2565,7 @@
     "java/src/org/chromium/chrome/browser/rlz/RevenueStats.java",
     "java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java",
     "java/src/org/chromium/chrome/browser/safe_browsing/FileTypePolicies.java",
-    "java/src/org/chromium/chrome/browser/search_engines/TemplateUrl.java",
-    "java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java",
+    "java/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceFactory.java",
     "java/src/org/chromium/chrome/browser/send_tab_to_self/NotificationManager.java",
     "java/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfAndroidBridge.java",
     "java/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfEntry.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index e4254cf..0e3a63f 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1356,8 +1356,7 @@
   "java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java",
   "java/src/org/chromium/chrome/browser/safe_browsing/FileTypePolicies.java",
   "java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java",
-  "java/src/org/chromium/chrome/browser/search_engines/TemplateUrl.java",
-  "java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java",
+  "java/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceFactory.java",
   "java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java",
   "java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java",
   "java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java",
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni
index 57efa6d..759e232 100644
--- a/chrome/android/chrome_junit_test_java_sources.gni
+++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -169,6 +169,7 @@
   "junit/src/org/chromium/chrome/browser/send_tab_to_self/NotificationSharedPrefManagerTest.java",
   "junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfAndroidBridgeTest.java",
   "junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivityTest.java",
+  "junit/src/org/chromium/chrome/browser/signin/ChromeSigninManagerDelegateTest.java",
   "junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java",
   "junit/src/org/chromium/chrome/browser/signin/SigninPromoUtilTest.java",
   "junit/src/org/chromium/chrome/browser/snackbar/SnackbarCollectionUnitTest.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index e17aba2..c4d8001f 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -392,7 +392,6 @@
   "javatests/src/org/chromium/chrome/browser/provider/ProviderTestRule.java",
   "javatests/src/org/chromium/chrome/browser/push_messaging/PushMessagingTest.java",
   "javatests/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTest.java",
-  "javatests/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTestUtils.java",
   "javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java",
   "javatests/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProviderTest.java",
   "javatests/src/org/chromium/chrome/browser/services/GoogleServicesManagerIntegrationTest.java",
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn
index 543701312..7c872566 100644
--- a/chrome/android/features/autofill_assistant/BUILD.gn
+++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -71,6 +71,7 @@
     "java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinator.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/AssistantPeekHeightCoordinator.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/AssistantSnackbar.java",
+    "java/src/org/chromium/chrome/browser/autofill_assistant/AssistantTagsForTesting.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactoryImpl.java",
@@ -154,6 +155,8 @@
 
   java_files = [
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantInfoBoxUiTest.java",
+    "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPaymentRequestTestHelper.java",
+    "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPaymentRequestUiTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/EditDistanceTest.java",
   ]
@@ -164,11 +167,13 @@
     "//base:base_java_test_support",
     "//chrome/android:chrome_java",
     "//chrome/android:chrome_test_util_java",
+    "//content/public/android:content_java",
     "//content/public/test/android:content_java_test_support",
     "//net/android:net_java_test_support",
     "//third_party/android_deps:com_android_support_design_java",
     "//third_party/android_deps:com_android_support_recyclerview_v7_java",
     "//third_party/android_support_test_runner:runner_java",
+    "//third_party/hamcrest:hamcrest_java",
     "//third_party/junit",
     "//third_party/mockito:mockito_java",
     "//ui/android:ui_full_java",
diff --git a/chrome/android/features/autofill_assistant/java/AndroidManifest.xml b/chrome/android/features/autofill_assistant/java/AndroidManifest.xml
index 6e47d63..1d3890a 100644
--- a/chrome/android/features/autofill_assistant/java/AndroidManifest.xml
+++ b/chrome/android/features/autofill_assistant/java/AndroidManifest.xml
@@ -3,9 +3,9 @@
     featureSplit="autofill_assistant"
     package="{{manifest_package}}">
 
-    <!-- For Chrome Modern use android:minSdkVersion="21". -->
+    <!-- For Chrome Modern we use android:minSdkVersion="21". -->
     <uses-sdk
-        android:minSdkVersion="24"
+        android:minSdkVersion="21"
         android:targetSdkVersion="{{target_sdk_version}}" />
 
     <dist:module
diff --git a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_onboarding.xml b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_onboarding.xml
index 29f09ae..00404bc 100644
--- a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_onboarding.xml
+++ b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_onboarding.xml
@@ -10,7 +10,7 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:paddingTop="12dp"
-    android:paddingBottom="@dimen/autofill_assistant_bottombar_vertical_spacing"
+    android:paddingBottom="14dp"
     android:paddingStart="24dp"
     android:paddingEnd="24dp"
     android:gravity="center_horizontal"
@@ -91,7 +91,7 @@
     </LinearLayout>
 
     <!-- Layout for the buttons -->
-    <Space android:layout_width="0dp" android:layout_height="24dp"/>
+    <Space android:layout_width="0dp" android:layout_height="18dp"/>
     <LinearLayout
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantTagsForTesting.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantTagsForTesting.java
new file mode 100644
index 0000000..96bda199
--- /dev/null
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantTagsForTesting.java
@@ -0,0 +1,18 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.autofill_assistant;
+
+/**
+ * Contains tags used for java UI tests.
+ *
+ * These tags are used to tag dynamically created views (i.e., without resource ID) to allow tests
+ * to easily retrieve and test them.
+ */
+public class AssistantTagsForTesting {
+    public static final String PAYMENT_REQUEST_ACCORDION_TAG = "accordion";
+    public static final String PAYMENT_REQUEST_CONTACT_DETAILS_SECTION_TAG = "contact";
+    public static final String PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_TAG = "payment";
+    public static final String PAYMENT_REQUEST_SHIPPING_ADDRESS_SECTION_TAG = "shipping";
+}
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestBinder.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestBinder.java
index 668a546..f7cf6e3 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestBinder.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestBinder.java
@@ -420,13 +420,6 @@
      */
     // TODO(crbug.com/806868): Move the logic to retrieve and filter payment methods to native.
     private void updateAvailablePaymentMethods(AssistantPaymentRequestModel model) {
-        WebContents webContents = model.get(AssistantPaymentRequestModel.WEB_CONTENTS);
-        if (webContents == null) {
-            model.set(
-                    AssistantPaymentRequestModel.SUPPORTED_PAYMENT_METHODS, Collections.emptyMap());
-            return;
-        }
-
         // Only enable 'basic-card' payment method.
         PaymentMethodData methodData = new PaymentMethodData();
         methodData.supportedMethod = BasicCardUtils.BASIC_CARD_METHOD_NAME;
@@ -460,11 +453,6 @@
     // TODO(crbug.com/806868): Move this logic to native.
     private void updateAvailableAutofillPaymentMethods(AssistantPaymentRequestModel model) {
         WebContents webContents = model.get(AssistantPaymentRequestModel.WEB_CONTENTS);
-        if (webContents == null) {
-            model.set(AssistantPaymentRequestModel.AVAILABLE_AUTOFILL_PAYMENT_METHODS,
-                    Collections.emptyList());
-            return;
-        }
 
         AutofillPaymentApp autofillPaymentApp = new AutofillPaymentApp(webContents);
         Map<String, PaymentMethodData> supportedPaymentMethods =
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestCoordinator.java
index cc4eb172..a1fdcea9 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestCoordinator.java
@@ -11,6 +11,7 @@
 import android.widget.LinearLayout;
 
 import org.chromium.chrome.autofill_assistant.R;
+import org.chromium.chrome.browser.autofill_assistant.AssistantTagsForTesting;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
 // TODO(crbug.com/806868): Use mCarouselCoordinator to show chips.
@@ -66,6 +67,15 @@
         AssistantPaymentRequestTermsSection termsSection =
                 new AssistantPaymentRequestTermsSection(mActivity, paymentRequestExpanderAccordion);
 
+        paymentRequestExpanderAccordion.setTag(
+                AssistantTagsForTesting.PAYMENT_REQUEST_ACCORDION_TAG);
+        contactDetailsSection.getView().setTag(
+                AssistantTagsForTesting.PAYMENT_REQUEST_CONTACT_DETAILS_SECTION_TAG);
+        paymentMethodSection.getView().setTag(
+                AssistantTagsForTesting.PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_TAG);
+        shippingAddressSection.getView().setTag(
+                AssistantTagsForTesting.PAYMENT_REQUEST_SHIPPING_ADDRESS_SECTION_TAG);
+
         // Bind view and mediator through the model.
         mViewHolder = new AssistantPaymentRequestBinder.ViewHolder(mPaymentRequestUI,
                 paymentRequestExpanderAccordion, sectionToSectionPadding, contactDetailsSection,
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestModel.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestModel.java
index ccd4613..e579265 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestModel.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestModel.java
@@ -26,7 +26,7 @@
     // TODO(crbug.com/806868): add |setAvailableProfiles| and |setAvailablePaymentMethods| from
     // native. Implement |setShippingAddress|, |setContactDetails| and |setPaymentMethod|.
 
-    static final WritableObjectPropertyKey<AssistantPaymentRequestDelegate> DELEGATE =
+    public static final WritableObjectPropertyKey<AssistantPaymentRequestDelegate> DELEGATE =
             new WritableObjectPropertyKey<>();
 
     /** The web contents the payment request is associated with. */
@@ -83,6 +83,18 @@
                 REQUEST_PAYMENT, REQUEST_TERMS_AND_CONDITIONS, AVAILABLE_PROFILES,
                 AVAILABLE_AUTOFILL_PAYMENT_METHODS, SUPPORTED_BASIC_CARD_NETWORKS,
                 SUPPORTED_PAYMENT_METHODS, EXPANDED_SECTION);
+
+        /**
+         * Set initial state for basic type properties (others are implicitly null).
+         * This is necessary to ensure that the initial UI state is consistent with the model.
+         */
+        set(VISIBLE, false);
+        set(TERMS_STATUS, AssistantTermsAndConditionsState.NOT_SELECTED);
+        set(REQUEST_NAME, false);
+        set(REQUEST_EMAIL, false);
+        set(REQUEST_PHONE, false);
+        set(REQUEST_PAYMENT, false);
+        set(REQUEST_SHIPPING_ADDRESS, false);
     }
 
     @CalledByNative
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestPaymentMethodSection.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestPaymentMethodSection.java
index b1860c5c..f991848 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestPaymentMethodSection.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestPaymentMethodSection.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.autofill_assistant.payment;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.support.annotation.Nullable;
 import android.text.TextUtils;
 import android.view.View;
@@ -40,6 +41,18 @@
 
     public void setEditor(CardEditor editor) {
         mEditor = editor;
+        if (mEditor == null) {
+            return;
+        }
+
+        PersonalDataManager personalDataManager = PersonalDataManager.getInstance();
+        for (AutofillPaymentInstrument method : getItems()) {
+            String guid = method.getCard().getBillingAddressId();
+            PersonalDataManager.AutofillProfile profile = personalDataManager.getProfile(guid);
+            if (profile != null) {
+                addAutocompleteInformationToEditor(profile);
+            }
+        }
     }
 
     @Override
@@ -71,9 +84,15 @@
         if (method == null) {
             return;
         }
+
         ImageView cardIssuerImageView = summaryView.findViewById(R.id.credit_card_issuer_icon);
-        cardIssuerImageView.setImageDrawable(summaryView.getContext().getResources().getDrawable(
-                method.getCard().getIssuerIconDrawableId()));
+        try {
+            cardIssuerImageView.setImageDrawable(
+                    summaryView.getContext().getResources().getDrawable(
+                            method.getCard().getIssuerIconDrawableId()));
+        } catch (Resources.NotFoundException e) {
+            cardIssuerImageView.setImageDrawable(null);
+        }
 
         /**
          * By default, the obfuscated number contains the issuer (e.g., 'Visa'). This is needlessly
@@ -98,9 +117,9 @@
     }
 
     void onProfilesChanged(List<PersonalDataManager.AutofillProfile> profiles) {
+        // TODO(crbug.com/806868): replace suggested billing addresses (remove if necessary).
         for (PersonalDataManager.AutofillProfile profile : profiles) {
-            // TODO(crbug.com/806868): replace suggested billing addresses (remove if necessary).
-            mEditor.updateBillingAddressIfComplete(new AutofillAddress(mContext, profile));
+            addAutocompleteInformationToEditor(profile);
         }
     }
 
@@ -125,4 +144,11 @@
         // Replace current set of items, keep selection if possible.
         setItems(paymentMethods, selectedMethodIndex);
     }
+
+    private void addAutocompleteInformationToEditor(PersonalDataManager.AutofillProfile profile) {
+        if (mEditor == null) {
+            return;
+        }
+        mEditor.updateBillingAddressIfComplete(new AutofillAddress(mContext, profile));
+    }
 }
\ No newline at end of file
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPaymentRequestTestHelper.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPaymentRequestTestHelper.java
new file mode 100644
index 0000000..d301e6c
--- /dev/null
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPaymentRequestTestHelper.java
@@ -0,0 +1,108 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.autofill_assistant;
+
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.chrome.browser.autofill.PersonalDataManager;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
+import org.chromium.chrome.browser.autofill_assistant.payment.AssistantPaymentRequestCoordinator;
+import org.chromium.chrome.browser.autofill_assistant.payment.AssistantVerticalExpander;
+import org.chromium.chrome.browser.autofill_assistant.payment.AssistantVerticalExpanderAccordion;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Helper class for testing autofill assistant payment request. Code adapted from
+ * https://cs.chromium.org/chromium/src/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java
+ */
+public class AutofillAssistantPaymentRequestTestHelper {
+    private final CallbackHelper mOnPersonalDataChangedHelper = new CallbackHelper();
+
+    /** Extracts the views from a coordinator. */
+    static class ViewHolder {
+        final AssistantVerticalExpanderAccordion mAccordion;
+        final AssistantVerticalExpander mContactSection;
+        final AssistantVerticalExpander mPaymentSection;
+        final AssistantVerticalExpander mShippingSection;
+
+        ViewHolder(AssistantPaymentRequestCoordinator coordinator) {
+            mAccordion = coordinator.getView().findViewWithTag(
+                    AssistantTagsForTesting.PAYMENT_REQUEST_ACCORDION_TAG);
+            mContactSection = coordinator.getView().findViewWithTag(
+                    AssistantTagsForTesting.PAYMENT_REQUEST_CONTACT_DETAILS_SECTION_TAG);
+            mPaymentSection = coordinator.getView().findViewWithTag(
+                    AssistantTagsForTesting.PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_TAG);
+            mShippingSection = coordinator.getView().findViewWithTag(
+                    AssistantTagsForTesting.PAYMENT_REQUEST_SHIPPING_ADDRESS_SECTION_TAG);
+        }
+    }
+
+    public AutofillAssistantPaymentRequestTestHelper()
+            throws TimeoutException, InterruptedException {
+        registerDataObserver();
+        setRequestTimeoutForTesting();
+        setSyncServiceForTesting();
+    }
+
+    void setRequestTimeoutForTesting() {
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> PersonalDataManager.getInstance().setRequestTimeoutForTesting(0));
+    }
+
+    void setSyncServiceForTesting() {
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> PersonalDataManager.getInstance().setSyncServiceForTesting());
+    }
+
+    public String setProfile(final AutofillProfile profile)
+            throws TimeoutException, InterruptedException {
+        int callCount = mOnPersonalDataChangedHelper.getCallCount();
+        String guid = TestThreadUtils.runOnUiThreadBlockingNoException(
+                () -> PersonalDataManager.getInstance().setProfile(profile));
+        mOnPersonalDataChangedHelper.waitForCallback(callCount);
+        return guid;
+    }
+
+    public CreditCard getCreditCard(final String guid) {
+        return TestThreadUtils.runOnUiThreadBlockingNoException(
+                () -> PersonalDataManager.getInstance().getCreditCard(guid));
+    }
+
+    public String getShippingAddressLabelWithoutCountryForPaymentRequest(AutofillProfile profile) {
+        return TestThreadUtils.runOnUiThreadBlockingNoException(
+                ()
+                        -> PersonalDataManager.getInstance()
+                                   .getShippingAddressLabelWithoutCountryForPaymentRequest(
+                                           profile));
+    }
+
+    public String getShippingAddressLabelWithCountryForPaymentRequest(AutofillProfile profile) {
+        return TestThreadUtils.runOnUiThreadBlockingNoException(
+                ()
+                        -> PersonalDataManager.getInstance()
+                                   .getShippingAddressLabelWithCountryForPaymentRequest(profile));
+    }
+
+    public String setCreditCard(final CreditCard card)
+            throws TimeoutException, InterruptedException {
+        int callCount = mOnPersonalDataChangedHelper.getCallCount();
+        String guid = TestThreadUtils.runOnUiThreadBlockingNoException(
+                () -> PersonalDataManager.getInstance().setCreditCard(card));
+        mOnPersonalDataChangedHelper.waitForCallback(callCount);
+        return guid;
+    }
+
+    private void registerDataObserver() throws TimeoutException, InterruptedException {
+        int callCount = mOnPersonalDataChangedHelper.getCallCount();
+        boolean isDataLoaded = TestThreadUtils.runOnUiThreadBlockingNoException(
+                ()
+                        -> PersonalDataManager.getInstance().registerDataObserver(
+                                () -> mOnPersonalDataChangedHelper.notifyCalled()));
+        if (isDataLoaded) return;
+        mOnPersonalDataChangedHelper.waitForCallback(callCount);
+    }
+}
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPaymentRequestUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPaymentRequestUiTest.java
new file mode 100644
index 0000000..032e473
--- /dev/null
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPaymentRequestUiTest.java
@@ -0,0 +1,354 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.autofill_assistant;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import android.support.design.widget.CoordinatorLayout;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.autofill_assistant.R;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.autofill.CardType;
+import org.chromium.chrome.browser.autofill.PersonalDataManager;
+import org.chromium.chrome.browser.autofill_assistant.payment.AssistantChoiceList;
+import org.chromium.chrome.browser.autofill_assistant.payment.AssistantPaymentRequestCoordinator;
+import org.chromium.chrome.browser.autofill_assistant.payment.AssistantPaymentRequestModel;
+import org.chromium.chrome.browser.autofill_assistant.payment.AssistantTermsAndConditionsState;
+import org.chromium.chrome.browser.customtabs.CustomTabActivity;
+import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
+import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Tests for the Autofill Assistant payment request UI.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class AutofillAssistantPaymentRequestUiTest {
+    private AutofillAssistantPaymentRequestTestHelper mHelper;
+
+    @Rule
+    public CustomTabActivityTestRule mCustomTabActivityTestRule = new CustomTabActivityTestRule();
+
+    @Before
+    public void setUp() throws Exception {
+        mCustomTabActivityTestRule.startCustomTabActivityWithIntent(
+                CustomTabsTestUtils.createMinimalCustomTabIntent(
+                        InstrumentationRegistry.getTargetContext(), "about:blank"));
+        mHelper = new AutofillAssistantPaymentRequestTestHelper();
+    }
+
+    private CustomTabActivity getActivity() {
+        return mCustomTabActivityTestRule.getActivity();
+    }
+
+    /** Creates a coordinator for use in UI tests, and adds it to the global view hierarchy. */
+    private AssistantPaymentRequestCoordinator createPaymentRequestCoordinator(
+            AssistantPaymentRequestModel model) {
+        ThreadUtils.assertOnUiThread();
+        AssistantPaymentRequestCoordinator coordinator =
+                new AssistantPaymentRequestCoordinator(getActivity(), model);
+
+        CoordinatorLayout.LayoutParams lp = new CoordinatorLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+        lp.gravity = Gravity.BOTTOM;
+
+        ViewGroup chromeCoordinatorView = getActivity().findViewById(R.id.coordinator);
+        chromeCoordinatorView.addView(coordinator.getView(), lp);
+
+        return coordinator;
+    }
+
+    /**
+     * Test assumptions about the initial state of the payment request.
+     */
+    @Test
+    @MediumTest
+    public void testInitialState() {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            AssistantPaymentRequestModel model = new AssistantPaymentRequestModel();
+            AssistantPaymentRequestCoordinator coordinator = createPaymentRequestCoordinator(model);
+
+            assertFalse(model.get(AssistantPaymentRequestModel.VISIBLE));
+            assertFalse("PR is initially invisible", coordinator.getView().isShown());
+            assertNull("Initially, the model should not contain any profiles",
+                    model.get(AssistantPaymentRequestModel.AVAILABLE_PROFILES));
+            assertNull("Initially, the model should not contain any payment methods",
+                    model.get(AssistantPaymentRequestModel.AVAILABLE_AUTOFILL_PAYMENT_METHODS));
+            assertNull("Initially, no payment method is supported",
+                    model.get(AssistantPaymentRequestModel.SUPPORTED_PAYMENT_METHODS));
+            assertNull("Initially, no basic card network filter is set",
+                    model.get(AssistantPaymentRequestModel.SUPPORTED_BASIC_CARD_NETWORKS));
+            assertNull("Initially, no section is expanded",
+                    model.get(AssistantPaymentRequestModel.EXPANDED_SECTION));
+            assertNull(model.get(AssistantPaymentRequestModel.DELEGATE));
+            assertNull(model.get(AssistantPaymentRequestModel.WEB_CONTENTS));
+            assertNull(model.get(AssistantPaymentRequestModel.SHIPPING_ADDRESS));
+            assertNull(model.get(AssistantPaymentRequestModel.PAYMENT_METHOD));
+            assertNull(model.get(AssistantPaymentRequestModel.CONTACT_DETAILS));
+            assertEquals(AssistantTermsAndConditionsState.NOT_SELECTED,
+                    model.get(AssistantPaymentRequestModel.TERMS_STATUS));
+
+            /** Test initial UI state. */
+            AutofillAssistantPaymentRequestTestHelper.ViewHolder viewHolder =
+                    new AutofillAssistantPaymentRequestTestHelper.ViewHolder(coordinator);
+            assertFalse(viewHolder.mContactSection.isExpanded());
+            assertFalse(viewHolder.mPaymentSection.isExpanded());
+            assertFalse(viewHolder.mShippingSection.isExpanded());
+        });
+    }
+
+    /**
+     * Sections become visible/invisible depending on model changes.
+     */
+    @Test
+    @MediumTest
+    public void testSectionVisibility() {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            AssistantPaymentRequestModel model = new AssistantPaymentRequestModel();
+            AssistantPaymentRequestCoordinator coordinator = createPaymentRequestCoordinator(model);
+
+            AutofillAssistantPaymentRequestTestHelper.ViewHolder viewHolder =
+                    new AutofillAssistantPaymentRequestTestHelper.ViewHolder(coordinator);
+
+            /** Initially, everything is invisible. */
+            assertFalse(coordinator.getView().isShown());
+
+            /** PR is visible, but no section was requested: all sections should be invisible. */
+            model.set(AssistantPaymentRequestModel.VISIBLE, true);
+            assertTrue(coordinator.getView().isShown());
+            assertFalse(viewHolder.mContactSection.isShown());
+            assertFalse(viewHolder.mPaymentSection.isShown());
+            assertFalse(viewHolder.mShippingSection.isShown());
+
+            /** Contact details should be visible if either name, phone, or email is requested. */
+            model.set(AssistantPaymentRequestModel.REQUEST_NAME, true);
+            assertTrue(viewHolder.mContactSection.isShown());
+            assertFalse(viewHolder.mPaymentSection.isShown());
+            assertFalse(viewHolder.mShippingSection.isShown());
+
+            model.set(AssistantPaymentRequestModel.REQUEST_NAME, false);
+            model.set(AssistantPaymentRequestModel.REQUEST_PHONE, true);
+            assertTrue(viewHolder.mContactSection.isShown());
+            assertFalse(viewHolder.mPaymentSection.isShown());
+            assertFalse(viewHolder.mShippingSection.isShown());
+
+            model.set(AssistantPaymentRequestModel.REQUEST_PHONE, false);
+            model.set(AssistantPaymentRequestModel.REQUEST_EMAIL, true);
+            assertTrue(viewHolder.mContactSection.isShown());
+            assertFalse(viewHolder.mPaymentSection.isShown());
+            assertFalse(viewHolder.mShippingSection.isShown());
+
+            model.set(AssistantPaymentRequestModel.REQUEST_NAME, true);
+            model.set(AssistantPaymentRequestModel.REQUEST_PHONE, true);
+            model.set(AssistantPaymentRequestModel.REQUEST_EMAIL, true);
+            assertTrue(viewHolder.mContactSection.isShown());
+            assertFalse(viewHolder.mPaymentSection.isShown());
+            assertFalse(viewHolder.mShippingSection.isShown());
+
+            /** Payment method section visibility test. */
+            model.set(AssistantPaymentRequestModel.REQUEST_PAYMENT, true);
+            assertTrue(viewHolder.mPaymentSection.isShown());
+
+            /** Shipping address visibility test. */
+            model.set(AssistantPaymentRequestModel.REQUEST_SHIPPING_ADDRESS, true);
+            assertTrue(viewHolder.mShippingSection.isShown());
+        });
+    }
+
+    /**
+     * Test assumptions about a payment request for a case where the personal data manager does not
+     * contain any profiles or payment methods, i.e., all PR sections should be empty.
+     */
+    @Test
+    @MediumTest
+    public void testEmptyPaymentRequest() {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            AssistantPaymentRequestModel model = new AssistantPaymentRequestModel();
+            AssistantPaymentRequestCoordinator coordinator = createPaymentRequestCoordinator(model);
+
+            /** Request all PR sections. */
+            model.set(AssistantPaymentRequestModel.REQUEST_NAME, true);
+            model.set(AssistantPaymentRequestModel.REQUEST_PHONE, true);
+            model.set(AssistantPaymentRequestModel.REQUEST_EMAIL, true);
+            model.set(AssistantPaymentRequestModel.REQUEST_PAYMENT, true);
+            model.set(AssistantPaymentRequestModel.REQUEST_SHIPPING_ADDRESS, true);
+            model.set(AssistantPaymentRequestModel.VISIBLE, true);
+
+            AutofillAssistantPaymentRequestTestHelper.ViewHolder viewHolder =
+                    new AutofillAssistantPaymentRequestTestHelper.ViewHolder(coordinator);
+
+            /** Empty sections should display the 'add' button in their title. */
+            assertTrue(viewHolder.mContactSection.findViewById(R.id.section_title_add_button)
+                               .isShown());
+            assertTrue(viewHolder.mPaymentSection.findViewById(R.id.section_title_add_button)
+                               .isShown());
+            assertTrue(viewHolder.mShippingSection.findViewById(R.id.section_title_add_button)
+                               .isShown());
+
+            /** Empty sections should be 'fixed', i.e., they can not be expanded. */
+            assertTrue(viewHolder.mContactSection.isFixed());
+            assertTrue(viewHolder.mPaymentSection.isFixed());
+            assertTrue(viewHolder.mShippingSection.isFixed());
+
+            /** Empty sections are collapsed. */
+            assertFalse(viewHolder.mContactSection.isExpanded());
+            assertFalse(viewHolder.mPaymentSection.isExpanded());
+            assertFalse(viewHolder.mShippingSection.isExpanded());
+
+            /** Empty sections should be empty. */
+            AssistantChoiceList contactsList =
+                    viewHolder.mContactSection.findViewById(R.id.section_choice_list);
+            AssistantChoiceList paymentsList =
+                    viewHolder.mPaymentSection.findViewById(R.id.section_choice_list);
+            AssistantChoiceList shippingList =
+                    viewHolder.mShippingSection.findViewById(R.id.section_choice_list);
+            assertEquals(0, contactsList.getItemCount());
+            assertEquals(0, paymentsList.getItemCount());
+            assertEquals(0, shippingList.getItemCount());
+        });
+    }
+
+    /**
+     * Test assumptions about a payment request for a personal data manager with a complete profile
+     * and payment method, i.e., all PR sections should be non-empty.
+     */
+    @Test
+    @MediumTest
+    public void testNonEmptyPaymentRequest() throws TimeoutException, InterruptedException {
+        /**
+         * Add complete profile and credit card to the personal data manager. Must be done outside
+         * UI thread!
+         */
+        PersonalDataManager.AutofillProfile profile = new PersonalDataManager.AutofillProfile(
+                "" /* guid */, "https://www.example.com" /* origin */, "Maggie Simpson",
+                "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "Uzbekistan",
+                "555 123-4567", "maggie@simpson.com", "");
+        String billingAddressId = mHelper.setProfile(profile);
+        PersonalDataManager.CreditCard creditCard = new PersonalDataManager.CreditCard("",
+                "https://example.com", true, true, "Jon Doe", "4111111111111111", "1111", "12",
+                "2050", "visa", org.chromium.chrome.R.drawable.visa_card, CardType.UNKNOWN,
+                billingAddressId, "" /* serverId */);
+        mHelper.setCreditCard(creditCard);
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            AssistantPaymentRequestModel model = new AssistantPaymentRequestModel();
+            AssistantPaymentRequestCoordinator coordinator = createPaymentRequestCoordinator(model);
+
+            /** Request all PR sections. */
+            model.set(AssistantPaymentRequestModel.REQUEST_NAME, true);
+            model.set(AssistantPaymentRequestModel.REQUEST_PHONE, true);
+            model.set(AssistantPaymentRequestModel.REQUEST_EMAIL, true);
+            model.set(AssistantPaymentRequestModel.REQUEST_PAYMENT, true);
+            model.set(AssistantPaymentRequestModel.REQUEST_SHIPPING_ADDRESS, true);
+            model.set(AssistantPaymentRequestModel.VISIBLE, true);
+
+            AutofillAssistantPaymentRequestTestHelper.ViewHolder viewHolder =
+                    new AutofillAssistantPaymentRequestTestHelper.ViewHolder(coordinator);
+
+            /** Non-empty sections should not display the 'add' button in their title. */
+            assertFalse(viewHolder.mContactSection.findViewById(R.id.section_title_add_button)
+                                .isShown());
+            assertFalse(viewHolder.mPaymentSection.findViewById(R.id.section_title_add_button)
+                                .isShown());
+            assertFalse(viewHolder.mShippingSection.findViewById(R.id.section_title_add_button)
+                                .isShown());
+
+            /** Non-empty sections should not be 'fixed', i.e., they can be expanded. */
+            assertFalse(viewHolder.mContactSection.isFixed());
+            assertFalse(viewHolder.mPaymentSection.isFixed());
+            assertFalse(viewHolder.mShippingSection.isFixed());
+
+            /** Check contents of sections. */
+            AssistantChoiceList contactsList =
+                    viewHolder.mContactSection.findViewById(R.id.section_choice_list);
+            AssistantChoiceList paymentsList =
+                    viewHolder.mPaymentSection.findViewById(R.id.section_choice_list);
+            AssistantChoiceList shippingList =
+                    viewHolder.mShippingSection.findViewById(R.id.section_choice_list);
+            assertEquals(1, contactsList.getItemCount());
+            assertEquals(1, paymentsList.getItemCount());
+            assertEquals(1, shippingList.getItemCount());
+            testContact("maggie@simpson.com", "Maggie Simpson\nmaggie@simpson.com",
+                    viewHolder.mContactSection.getCollapsedView(), contactsList.getItem(0));
+            testPaymentMethod("1111", "Jon Doe", "12/2050",
+                    viewHolder.mPaymentSection.getCollapsedView(), paymentsList.getItem(0));
+            testShippingAddress("Maggie Simpson",
+                    "Acme Inc., 123 Main, 90210 Los Angeles, California",
+                    "Acme Inc., 123 Main, 90210 Los Angeles, California, Uzbekistan",
+                    viewHolder.mShippingSection.getCollapsedView(), shippingList.getItem(0));
+        });
+    }
+
+    private void testContact(String expectedContactSummary, String expectedContactFullDescription,
+            View summaryView, View fullView) {
+        TextView contactSummary = summaryView.findViewById(R.id.contact_summary);
+        assertEquals(expectedContactSummary, contactSummary.getText());
+        assertFalse(summaryView.findViewById(R.id.incomplete_error).isShown());
+
+        TextView contactFull = fullView.findViewById(R.id.contact_full);
+        assertEquals(expectedContactFullDescription, contactFull.getText());
+        assertFalse(fullView.findViewById(R.id.incomplete_error).isShown());
+    }
+
+    private void testPaymentMethod(String expectedObfuscatedCardNumber, String expectedCardName,
+            String expectedCardExpiration, View summaryView, View fullView) {
+        TextView paymentMethodNumber = summaryView.findViewById(R.id.credit_card_number);
+        testCreditCardNumber(expectedObfuscatedCardNumber, paymentMethodNumber);
+        TextView paymentMethodExpirationDate =
+                summaryView.findViewById(R.id.credit_card_expiration);
+        assertEquals(expectedCardExpiration, paymentMethodExpirationDate.getText());
+        assertNull(summaryView.findViewById(R.id.credit_card_name));
+        assertFalse(summaryView.findViewById(R.id.incomplete_error).isShown());
+
+        paymentMethodNumber = fullView.findViewById(R.id.credit_card_number);
+        testCreditCardNumber(expectedObfuscatedCardNumber, paymentMethodNumber);
+        paymentMethodExpirationDate = fullView.findViewById(R.id.credit_card_expiration);
+        assertEquals(expectedCardExpiration, paymentMethodExpirationDate.getText());
+        TextView paymentMethodCardName = fullView.findViewById(R.id.credit_card_name);
+        assertEquals(expectedCardName, paymentMethodCardName.getText());
+        assertFalse(fullView.findViewById(R.id.incomplete_error).isShown());
+    }
+
+    private void testCreditCardNumber(String expectedObfuscatedNumber, TextView actual) {
+        assertThat(actual.getText().toString(), containsString(expectedObfuscatedNumber));
+    }
+
+    private void testShippingAddress(String expectedFullName, String expectedShortAddress,
+            String expectedFullAddress, View summaryView, View fullView) {
+        TextView addressName = summaryView.findViewById(R.id.full_name);
+        assertEquals(expectedFullName, addressName.getText());
+        TextView addressShort = summaryView.findViewById(R.id.short_address);
+        assertEquals(expectedShortAddress, addressShort.getText());
+        assertFalse(summaryView.findViewById(R.id.incomplete_error).isShown());
+
+        addressName = fullView.findViewById(R.id.full_name);
+        assertEquals(expectedFullName, addressName.getText());
+        TextView addressFull = fullView.findViewById(R.id.full_address);
+        assertEquals(expectedFullAddress, addressFull.getText());
+        assertFalse(fullView.findViewById(R.id.incomplete_error).isShown());
+    }
+}
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java
index 5f2bc783..ac99548 100644
--- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java
+++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java
@@ -4,7 +4,9 @@
 
 package org.chromium.chrome.browser.autofill_assistant;
 
+import org.chromium.base.BundleUtils;
 import org.chromium.base.Callback;
+import org.chromium.base.SysUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.ChromeActivity;
@@ -16,7 +18,7 @@
  * Manages the loading of autofill assistant DFM, and provides implementation of
  * AutofillAssistantModuleEntry.
  */
-class AutofillAssistantModuleEntryProvider {
+public class AutofillAssistantModuleEntryProvider {
     /**
      * Returns AutofillAssistantModuleEntry by using it as argument to the
      * passed in callback, or null if DFM loading fails.
@@ -34,6 +36,27 @@
         });
     }
 
+    /**
+     * Maybe trigger a deferred install of the module.
+     *
+     * <p>This is public so that it can be used in the Chrome upgrade package. The conditions for
+     * eligibility are:
+     *
+     * <ul>
+     *   <li>This is a Bundle build.
+     *   <li>The autofill_assistant DFM is not installed yet.
+     *   <li>The Android version is L+.
+     *   <li>The device has high disk capacity.
+     * </ul>
+     */
+    public static void maybeInstallDeferred() {
+        if (!BundleUtils.isBundle()) return;
+        if (AutofillAssistantModule.isInstalled()) return;
+        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) return;
+        if (!SysUtils.isHighEndDiskDevice()) return;
+        AutofillAssistantModule.installDeferred();
+    }
+
     private static AutofillAssistantModuleEntry createEntry(Tab tab) {
         AutofillAssistantModuleEntryFactory factory = AutofillAssistantModule.getImpl();
         return factory.createEntry(tab.getWebContents());
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_address_info.xml b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_address_info.xml
index fcac328..a06df67 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_address_info.xml
+++ b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_address_info.xml
@@ -32,6 +32,7 @@
         <org.chromium.ui.widget.ChipView
             android:id="@+id/name_middle"
             android:gravity="center_vertical|start"
+            android:layout_marginStart="@dimen/keyboard_accessory_sheet_padding"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             style="@style/InputChip" />
@@ -39,6 +40,7 @@
         <org.chromium.ui.widget.ChipView
             android:id="@+id/name_last"
             android:gravity="center_vertical|start"
+            android:layout_marginStart="@dimen/keyboard_accessory_sheet_padding"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             style="@style/InputChip" />
@@ -83,6 +85,7 @@
         <org.chromium.ui.widget.ChipView
             android:id="@+id/address_home_city"
             android:gravity="center_vertical|start"
+            android:layout_marginStart="@dimen/keyboard_accessory_sheet_padding"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             style="@style/InputChip" />
@@ -90,6 +93,7 @@
         <org.chromium.ui.widget.ChipView
             android:id="@+id/address_home_zip"
             android:gravity="center_vertical|start"
+            android:layout_marginStart="@dimen/keyboard_accessory_sheet_padding"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             style="@style/InputChip" />
@@ -99,6 +103,8 @@
     <org.chromium.ui.widget.ChipView
         android:id="@+id/address_home_country"
         android:gravity="center_vertical|start"
+        android:layout_marginTop="@dimen/keyboard_accessory_sheet_padding"
+        android:layout_marginBottom="@dimen/keyboard_accessory_sheet_padding"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         style="@style/InputChip" />
@@ -117,4 +123,8 @@
         android:layout_height="wrap_content"
         style="@style/InputChip" />
 
+    <View style="@style/HorizontalDivider"
+        android:layout_marginTop="@dimen/keyboard_accessory_sheet_divider_margin"
+        android:layout_marginBottom="0dp" />
+
 </org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.AddressAccessoryInfoView>
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_credit_card_info.xml b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_credit_card_info.xml
index ee24da8d..2f000bc5b 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_credit_card_info.xml
+++ b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_credit_card_info.xml
@@ -14,73 +14,87 @@
     android:paddingEnd="@dimen/keyboard_accessory_suggestion_padding"
     android:layout_marginTop="@dimen/keyboard_accessory_sheet_top_margin"
     android:layout_marginBottom="@dimen/keyboard_accessory_sheet_bottom_margin"
-    android:orientation="horizontal">
+    android:orientation="vertical">
 
     <LinearLayout
         android:gravity="center_vertical|start"
         android:fillViewport="true"
         android:layout_height="wrap_content"
-        android:layout_width="0dp"
-        android:layout_weight="1"
-        android:orientation="vertical">
-
-        <org.chromium.ui.widget.ChipView
-            android:id="@+id/cc_number"
-            android:gravity="center_vertical|start"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            style="@style/InputChip" />
+        android:layout_width="match_parent"
+        android:orientation="horizontal">
 
         <LinearLayout
             android:gravity="center_vertical|start"
             android:fillViewport="true"
-            android:layout_height="@dimen/keyboard_accessory_suggestion_height"
-            android:layout_width="match_parent"
-            android:orientation="horizontal">
+            android:layout_height="wrap_content"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:orientation="vertical">
 
             <org.chromium.ui.widget.ChipView
-                android:id="@+id/exp_month"
+                android:id="@+id/cc_number"
                 android:gravity="center_vertical|start"
+                android:layout_marginBottom="@dimen/keyboard_accessory_sheet_padding"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 style="@style/InputChip" />
 
-            <TextView
-                android:text="/"
-                tools:ignore="HardcodedText"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingStart="@dimen/keyboard_accessory_sheet_padding"
-                android:paddingEnd="@dimen/keyboard_accessory_sheet_padding"
-                android:textAppearance="@style/TextAppearance.BlackHint1"
-             />
+            <LinearLayout
+                android:gravity="center_vertical|start"
+                android:fillViewport="true"
+                android:layout_height="@dimen/keyboard_accessory_suggestion_height"
+                android:layout_width="match_parent"
+                android:orientation="horizontal">
+
+                <org.chromium.ui.widget.ChipView
+                    android:id="@+id/exp_month"
+                    android:gravity="center_vertical|start"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    style="@style/InputChip" />
+
+                <TextView
+                    android:text="/"
+                    tools:ignore="HardcodedText"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="@dimen/keyboard_accessory_sheet_padding"
+                    android:layout_marginEnd="@dimen/keyboard_accessory_sheet_padding"
+                    android:textAppearance="@style/TextAppearance.BlackHint1"
+                    />
+
+                <org.chromium.ui.widget.ChipView
+                    android:id="@+id/exp_year"
+                    android:gravity="center_vertical|start"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    style="@style/InputChip" />
+
+            </LinearLayout>
+
 
             <org.chromium.ui.widget.ChipView
-                android:id="@+id/exp_year"
+                android:id="@+id/cardholder"
                 android:gravity="center_vertical|start"
+                android:layout_marginTop="@dimen/keyboard_accessory_sheet_padding"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 style="@style/InputChip" />
 
         </LinearLayout>
 
-
-    <org.chromium.ui.widget.ChipView
-        android:id="@+id/cardholder"
-        android:gravity="center_vertical|start"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        style="@style/InputChip" />
-
+        <!-- TODO(crbug.com/969708): Replace placeholder dimensions once icon is replaced -->
+        <ImageView
+            android:id="@+id/icon"
+            android:layout_width="@dimen/keyboard_accessory_suggestion_icon_size"
+            android:layout_height="@dimen/keyboard_accessory_suggestion_icon_size"
+            android:layout_weight="0"
+            android:importantForAccessibility="no"
+            android:layout_gravity="top|end" />
     </LinearLayout>
 
-    <!-- TODO(crbug.com/969708): Replace placeholder dimensions once icon is replaced -->
-    <ImageView
-        android:id="@+id/icon"
-        android:layout_width="@dimen/keyboard_accessory_suggestion_icon_size"
-        android:layout_height="@dimen/keyboard_accessory_suggestion_icon_size"
-        android:layout_weight="0"
-        android:importantForAccessibility="no"
-        android:layout_gravity="top|end" />
+    <View style="@style/HorizontalDivider"
+        android:layout_marginTop="@dimen/keyboard_accessory_sheet_divider_margin"
+        android:layout_marginBottom="0dp" />
 
 </org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.CreditCardAccessoryInfoView>
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_password_info.xml b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_password_info.xml
index 87ad1f85..96662ed 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_password_info.xml
+++ b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_password_info.xml
@@ -51,4 +51,8 @@
         android:layout_height="wrap_content"
         style="@style/InputChip" />
 
+    <View style="@style/HorizontalDivider"
+        android:layout_marginTop="@dimen/keyboard_accessory_sheet_divider_margin"
+        android:layout_marginBottom="0dp" />
+
 </org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.PasswordAccessoryInfoView>
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_tabs.xml b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_tabs.xml
index 0ff34f6f..b23f48d 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_tabs.xml
+++ b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_tabs.xml
@@ -8,6 +8,9 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     app:tabIndicatorHeight="@dimen/divider_height"
     app:tabTextColor="@color/default_icon_color"
+    app:tabMaxWidth="@dimen/keyboard_accessory_tab_icon_width"
+    app:tabPaddingStart="@dimen/keyboard_accessory_bar_item_padding"
+    app:tabPaddingEnd="@dimen/keyboard_accessory_bar_item_padding"
     app:tabSelectedTextColor="@color/tab_layout_selected_tab_color"
     android:layout_gravity="end"
     android:layout_width="wrap_content"
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/values/dimens.xml b/chrome/android/features/keyboard_accessory/internal/java/res/values/dimens.xml
index 39fa865..b2a4b3bbd 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/res/values/dimens.xml
+++ b/chrome/android/features/keyboard_accessory/internal/java/res/values/dimens.xml
@@ -14,6 +14,7 @@
     <dimen name="keyboard_accessory_shadow">5dp</dimen>
     <dimen name="keyboard_accessory_chip_vertical_margin">8dp</dimen>
     <!--dimen name="keyboard_accessory_sheet_height">330dp</dimen-->
+    <dimen name="keyboard_accessory_sheet_divider_margin">24dp</dimen>
     <dimen name="keyboard_accessory_sheet_padding">8dp</dimen>
     <dimen name="keyboard_accessory_sheet_top_margin">16dp</dimen>
     <dimen name="keyboard_accessory_sheet_bottom_margin">8dp</dimen>
@@ -23,5 +24,6 @@
     <dimen name="keyboard_accessory_suggestion_icon_size">20dp</dimen>
     <dimen name="keyboard_accessory_scroll_shadow_width">40dp</dimen>
     <dimen name="keyboard_accessory_bar_item_cc_icon_width">32dp</dimen>
+    <dimen name="keyboard_accessory_tab_icon_width">40dp</dimen>
     <dimen name="keyboard_accessory_tab_size">@dimen/keyboard_accessory_height</dimen>
 </resources>
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewTest.java
index b8aa76b..04886db 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewTest.java
@@ -133,7 +133,9 @@
                     AccessorySheetDataPiece.Type.FOOTER_COMMAND));
         });
 
-        CriteriaHelper.pollUiThread(Criteria.equals(2, () -> mView.get().getChildCount()));
+        // Wait until at least one element is rendered. Test devices with small screens will cause
+        // the footer to not be created. Instantiating a footer still covers potential crashes.
+        CriteriaHelper.pollUiThread(() -> mView.get().getChildCount() > 0);
 
         // Check that the titles are correct:
         assertThat(getChipText(R.id.name_first), is("Maya"));
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java
index 52ac0e5..3ac5139 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java
@@ -46,7 +46,7 @@
 import org.chromium.chrome.browser.ntp.snippets.SectionHeaderView;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.signin.PersonalizedSigninPromoView;
 import org.chromium.chrome.browser.snackbar.Snackbar;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
@@ -283,7 +283,7 @@
 
         mNewTabPageLayout.initialize(mNewTabPageManager, mTab, mTileGroupDelegate,
                 mSearchProviderHasLogo,
-                TemplateUrlService.getInstance().isDefaultSearchEngineGoogle(), mMediator,
+                TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle(), mMediator,
                 mContextMenuManager, mUiConfig);
     }
 
diff --git a/chrome/android/java/DEPS b/chrome/android/java/DEPS
index 9992724a..99b62b2 100644
--- a/chrome/android/java/DEPS
+++ b/chrome/android/java/DEPS
@@ -20,6 +20,7 @@
   "+components/offline_items_collection/core/android/java",
   "+components/omnibox/browser/android/java",
   "+components/payments/content/android/java/src/org/chromium/components/payments",
+  "+components/search_engines/android/java/src/org/chromium/components/search_engines",
   "+components/sync/android/java/src/org/chromium/components/sync",
 
   "-content/public/android",
diff --git a/chrome/android/java/monochrome_public_bundle.proguard_flags.expected b/chrome/android/java/monochrome_public_bundle.proguard_flags.expected
index 7f2645a7..b1225fc 100644
--- a/chrome/android/java/monochrome_public_bundle.proguard_flags.expected
+++ b/chrome/android/java/monochrome_public_bundle.proguard_flags.expected
@@ -610,7 +610,8 @@
     native <methods>;
 }
 
--keep public class com.google.ar.core.** {*;}
+-keep public class !com.google.ar.core.viewer.**, !com.google.ar.core**.R$*, !com.google.ar.core.services.logging.**, com.google.ar.core.** {*;}
+
 # If you need to build a library on top of arcore_client, and use this library for your project
 # Please un-comment this line below.
 # -keepattributes *Annotation*
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeCallback.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeCallback.java
index bd1556d..42d30e0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeCallback.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActionModeCallback.java
@@ -16,7 +16,7 @@
 import org.chromium.chrome.browser.firstrun.FirstRunStatus;
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.omnibox.geo.GeolocationHeader;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
@@ -102,7 +102,7 @@
      */
     @VisibleForTesting
     protected LoadUrlParams generateUrlParamsForSearch(String query) {
-        String url = TemplateUrlService.getInstance().getUrlForSearchQuery(query);
+        String url = TemplateUrlServiceFactory.get().getUrlForSearchQuery(query);
         String headers = GeolocationHeader.getGeoHeader(url, mTab);
 
         LoadUrlParams loadUrlParams = new LoadUrlParams(url);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 657c16a..8dda68d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -117,9 +117,9 @@
 import org.chromium.chrome.browser.suggestions.SuggestionsEventReporterBridge;
 import org.chromium.chrome.browser.suggestions.SuggestionsMetrics;
 import org.chromium.chrome.browser.survey.ChromeSurveyController;
+import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabAssociatedApp;
-import org.chromium.chrome.browser.tab.TabBrowserControlsState;
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
 import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.chrome.browser.tab.TabStateBrowserControlsVisibilityDelegate;
@@ -455,11 +455,10 @@
         }
 
         @Override
-        public void createBrowserControlsState(Tab tab) {
-            TabBrowserControlsState.create(tab,
-                    new ComposedBrowserControlsVisibilityDelegate(
-                            new TabbedModeBrowserControlsVisibilityDelegate(tab),
-                            getFullscreenManager().getBrowserVisibilityDelegate()));
+        public BrowserControlsVisibilityDelegate createBrowserControlsVisibilityDelegate(Tab tab) {
+            return new ComposedBrowserControlsVisibilityDelegate(
+                    new TabbedModeBrowserControlsVisibilityDelegate(tab),
+                    getFullscreenManager().getBrowserVisibilityDelegate());
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
index 0bbb8790..efba2d1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -41,7 +41,7 @@
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteController;
 import org.chromium.chrome.browser.rappor.RapporServiceBridge;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabLaunchType;
 import org.chromium.chrome.browser.util.IntentUtils;
@@ -647,7 +647,7 @@
             if (urls != null && urls.size() > 0) {
                 url = urls.get(0);
             } else {
-                url = TemplateUrlService.getInstance().getUrlForVoiceSearchQuery(query);
+                url = TemplateUrlServiceFactory.get().getUrlForVoiceSearchQuery(query);
             }
         }
         return url;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
index 6f59e20a..845ffde 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
@@ -18,7 +18,6 @@
 import org.chromium.chrome.browser.tab.TabBuilder;
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
 import org.chromium.chrome.browser.tab.TabState;
-import org.chromium.chrome.browser.tab_activity_glue.TabDelegateFactoryImpl;
 import org.chromium.chrome.browser.tabmodel.SingleTabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
@@ -114,9 +113,7 @@
     /**
      * @return {@link TabDelegateFactory} to be used while creating the associated {@link Tab}.
      */
-    protected TabDelegateFactory createTabDelegateFactory() {
-        return new TabDelegateFactoryImpl(this);
-    }
+    protected abstract TabDelegateFactory createTabDelegateFactory();
 
     /**
      * Restore {@link TabState} from a given {@link Bundle} and tabId.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuItem.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuItem.java
index 6fbf8f5..3797583 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuItem.java
@@ -16,7 +16,7 @@
 import org.chromium.base.Callback;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.DefaultBrowserInfo;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.ui.text.SpanApplier;
 import org.chromium.ui.text.SpanApplier.SpanInfo;
@@ -167,7 +167,7 @@
                 return DefaultBrowserInfo.getTitleOpenInDefaultBrowser(false);
             case Item.SEARCH_BY_IMAGE:
                 return context.getString(getStringID(mItem),
-                        TemplateUrlService.getInstance()
+                        TemplateUrlServiceFactory.get()
                                 .getDefaultSearchEngineTemplateUrl()
                                 .getShortName());
             case Item.OPEN_IN_EPHEMERAL_TAB:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
index 2591222..be3f9a2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
@@ -23,10 +23,11 @@
 import org.chromium.chrome.browser.firstrun.FirstRunStatus;
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.share.ShareHelper;
 import org.chromium.chrome.browser.share.ShareParams;
 import org.chromium.chrome.browser.util.UrlUtilities;
+import org.chromium.components.search_engines.TemplateUrlService;
 import org.chromium.components.url_formatter.UrlFormatter;
 import org.chromium.content_public.browser.BrowserStartupController;
 import org.chromium.content_public.common.ContentUrlConstants;
@@ -546,7 +547,7 @@
      * @return The service that handles TemplateUrls.
      */
     protected TemplateUrlService getTemplateUrlService() {
-        return TemplateUrlService.getInstance();
+        return TemplateUrlServiceFactory.get();
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java
index 7b655f34..44c5b5ec 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java
@@ -9,7 +9,7 @@
 import android.text.TextUtils;
 
 import org.chromium.base.VisibleForTesting;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.util.UrlUtilities;
 
 import java.net.MalformedURLException;
@@ -221,7 +221,7 @@
      */
     protected Uri getUriTemplate(String query, @Nullable String alternateTerm, @Nullable String mid,
             boolean shouldPrefetch) {
-        Uri uri = Uri.parse(TemplateUrlService.getInstance().getUrlForContextualSearchQuery(
+        Uri uri = Uri.parse(TemplateUrlServiceFactory.get().getUrlForContextualSearchQuery(
                 query, alternateTerm, shouldPrefetch, CTXS_TWO_REQUEST_PROTOCOL));
         if (!TextUtils.isEmpty(mid)) uri = makeKPTriggeringUri(uri, mid);
         return uri;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java
index 62ce896..4f6c1f8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java
@@ -19,12 +19,12 @@
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.Tab.TabHidingType;
 import org.chromium.chrome.browser.tabmodel.TabSelectionType;
+import org.chromium.components.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
 import org.chromium.content_public.browser.GestureListenerManager;
 import org.chromium.content_public.browser.GestureStateListener;
 import org.chromium.content_public.browser.SelectionPopupController;
@@ -207,7 +207,7 @@
                 @Override
                 public void onTemplateURLServiceChanged() {
                     boolean isDefaultSearchEngineGoogle =
-                            TemplateUrlService.getInstance().isDefaultSearchEngineGoogle();
+                            TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle();
                     if (mIsDefaultSearchEngineGoogle == null
                             || isDefaultSearchEngineGoogle != mIsDefaultSearchEngineGoogle) {
                         mIsDefaultSearchEngineGoogle = isDefaultSearchEngineGoogle;
@@ -215,7 +215,7 @@
                     }
                 }
             };
-            TemplateUrlService.getInstance().addObserver(mTemplateUrlObserver);
+            TemplateUrlServiceFactory.get().addObserver(mTemplateUrlObserver);
         }
         updateHooksForTab(tab);
     }
@@ -232,7 +232,7 @@
             mNativeHelper = 0;
         }
         if (mTemplateUrlObserver != null) {
-            TemplateUrlService.getInstance().removeObserver(mTemplateUrlObserver);
+            TemplateUrlServiceFactory.get().removeObserver(mTemplateUrlObserver);
         }
         if (NetworkChangeNotifier.isInitialized()) {
             NetworkChangeNotifier.removeConnectionTypeObserver(this);
@@ -384,7 +384,7 @@
 
         return !webContents.isIncognito() && FirstRunStatus.getFirstRunFlowComplete()
                 && !PrefServiceBridge.getInstance().isContextualSearchDisabled()
-                && TemplateUrlService.getInstance().isDefaultSearchEngineGoogle()
+                && TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle()
                 && !LocaleManager.getInstance().needToCheckForSearchEnginePromo()
                 // Svelte and Accessibility devices are incompatible with the first-run flow and
                 // Talkback has poor interaction with tap to search (see http://crbug.com/399708 and
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
index 0bda3b8c..f5273d9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
@@ -27,7 +27,6 @@
 import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabAssociatedApp;
-import org.chromium.chrome.browser.tab.TabBrowserControlsState;
 import org.chromium.chrome.browser.tab.TabContextMenuItemDelegate;
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
 import org.chromium.chrome.browser.tab.TabStateBrowserControlsVisibilityDelegate;
@@ -270,7 +269,7 @@
     }
 
     @Override
-    public void createBrowserControlsState(Tab tab) {
+    public BrowserControlsVisibilityDelegate createBrowserControlsVisibilityDelegate(Tab tab) {
         TabStateBrowserControlsVisibilityDelegate tabDelegate =
                 new TabStateBrowserControlsVisibilityDelegate(tab) {
                     @Override
@@ -279,11 +278,12 @@
                     }
                 };
 
-        TabBrowserControlsState.create(tab,
-                mBrowserStateVisibilityDelegate == null
-                        ? tabDelegate
-                        : new ComposedBrowserControlsVisibilityDelegate(
-                                tabDelegate, mBrowserStateVisibilityDelegate));
+        // mBrowserStateVisibilityDelegate == null for background tabs for which
+        // fullscreen state info from BrowserStateVisibilityDelegate is not available.
+        return mBrowserStateVisibilityDelegate == null
+                ? tabDelegate
+                : new ComposedBrowserControlsVisibilityDelegate(
+                        tabDelegate, mBrowserStateVisibilityDelegate);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/DefaultSearchEngineFirstRunFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/DefaultSearchEngineFirstRunFragment.java
index 73f0a5d..1f306658 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/DefaultSearchEngineFirstRunFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/DefaultSearchEngineFirstRunFragment.java
@@ -17,7 +17,7 @@
 import org.chromium.chrome.browser.locale.DefaultSearchEngineDialogHelper;
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.locale.LocaleManager.SearchEnginePromoType;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.widget.RadioButtonLayout;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 
@@ -51,7 +51,7 @@
         mButton = (Button) rootView.findViewById(R.id.button_primary);
         mButton.setEnabled(false);
 
-        assert TemplateUrlService.getInstance().isLoaded();
+        assert TemplateUrlServiceFactory.get().isLoaded();
         mSearchEnginePromoDialoType = LocaleManager.getInstance().getSearchEnginePromoShowType();
         if (mSearchEnginePromoDialoType != LocaleManager.SearchEnginePromoType.DONT_SHOW) {
             Runnable dismissRunnable = new Runnable() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
index b30ae51..66f8b64 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
@@ -24,7 +24,7 @@
 import org.chromium.chrome.browser.datareduction.DataReductionProxyUma;
 import org.chromium.chrome.browser.metrics.UmaUtils;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.searchwidget.SearchWidgetProvider;
 import org.chromium.ui.base.LocalizationUtils;
 
@@ -257,7 +257,7 @@
                 onNativeDependenciesFullyInitialized();
             }
         };
-        TemplateUrlService.getInstance().runWhenLoaded(onNativeFinished);
+        TemplateUrlServiceFactory.get().runWhenLoaded(onNativeFinished);
     }
 
     public boolean isNativeSideIsInitializedForTest() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserStateBrowserControlsVisibilityDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserStateBrowserControlsVisibilityDelegate.java
index 70b9d1c..d40aa00 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserStateBrowserControlsVisibilityDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserStateBrowserControlsVisibilityDelegate.java
@@ -7,6 +7,7 @@
 import android.os.Handler;
 import android.os.SystemClock;
 
+import org.chromium.base.Supplier;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
 
@@ -27,6 +28,9 @@
 
     private final Handler mHandler = new Handler();
 
+    /** Predicate that tells if we're in persistent fullscreen mode. */
+    private final Supplier<Boolean> mPersistentFullscreenMode;
+
     private long mCurrentShowingStartTime;
 
     /**
@@ -35,9 +39,12 @@
      *
      * @param stateChangedCallback The callback to be triggered when the fullscreen state should be
      *                             updated based on the state of the browser visibility override.
+     * @param persistentFullscreenMode Predicate that tells if we're in persistent fullscreen mode.
      */
-    public BrowserStateBrowserControlsVisibilityDelegate(Runnable stateChangedCallback) {
+    public BrowserStateBrowserControlsVisibilityDelegate(
+            Runnable stateChangedCallback, Supplier<Boolean> persistentFullscreenMode) {
         mTokenHolder = new TokenHolder(stateChangedCallback);
+        mPersistentFullscreenMode = persistentFullscreenMode;
     }
 
     private void ensureControlsVisibleForMinDuration() {
@@ -98,7 +105,7 @@
 
     @Override
     public boolean canShowBrowserControls() {
-        return true;
+        return !mPersistentFullscreenMode.get();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
index 1ee5512..1f7e12d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
@@ -175,8 +175,8 @@
         mActivity = activity;
         mControlsPosition = controlsPosition;
         mExitFullscreenOnStop = exitFullscreenOnStop;
-        mBrowserVisibilityDelegate = new BrowserStateBrowserControlsVisibilityDelegate(
-                new Runnable() {
+        mBrowserVisibilityDelegate =
+                new BrowserStateBrowserControlsVisibilityDelegate(new Runnable() {
                     @Override
                     public void run() {
                         if (getTab() != null) {
@@ -185,7 +185,7 @@
                             setPositionsForTabToNonFullscreen();
                         }
                     }
-                });
+                }, this::getPersistentFullscreenMode);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/NativeStartupBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/init/NativeStartupBridge.java
index 17557de..dda29fe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/NativeStartupBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/NativeStartupBridge.java
@@ -24,12 +24,7 @@
                         .isStartupSuccessfullyCompleted()) {
             return;
         }
-        final BrowserParts parts = new EmptyBrowserParts() {
-            @Override
-            public boolean startServiceManagerOnly() {
-                return false;
-            }
-        };
+        final BrowserParts parts = new EmptyBrowserParts() {};
 
         PostTask.postTask(UiThreadTaskTraits.DEFAULT, new Runnable() {
             @Override
@@ -44,4 +39,16 @@
             }
         });
     }
+
+    @CalledByNative
+    private static void handlePostNativeStartupSynchronously() {
+        final BrowserParts parts = new EmptyBrowserParts() {};
+        try {
+            ChromeBrowserInitializer.getInstance().handlePostNativeStartup(
+                    /*isAsync=*/false, parts);
+        } catch (ProcessInitException e) {
+            Log.e(TAG, "Cannot handlePostNativeStartup synchronously.", e);
+            System.exit(-1);
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelper.java
index 5a21cb2..370970f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelper.java
@@ -12,8 +12,8 @@
 import android.widget.RadioGroup.OnCheckedChangeListener;
 
 import org.chromium.chrome.browser.locale.LocaleManager.SearchEnginePromoType;
-import org.chromium.chrome.browser.search_engines.TemplateUrl;
 import org.chromium.chrome.browser.widget.RadioButtonLayout;
+import org.chromium.components.search_engines.TemplateUrl;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java b/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
index 562ee59..5dcb8419 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
@@ -27,14 +27,14 @@
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.preferences.PreferencesLauncher;
 import org.chromium.chrome.browser.preferences.SearchEnginePreference;
-import org.chromium.chrome.browser.search_engines.TemplateUrl;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.snackbar.Snackbar;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController;
 import org.chromium.chrome.browser.vr.OnExitVrRequestListener;
 import org.chromium.chrome.browser.vr.VrModuleProvider;
 import org.chromium.chrome.browser.widget.PromoDialog;
+import org.chromium.components.search_engines.TemplateUrl;
 import org.chromium.ui.base.PageTransition;
 
 import java.lang.annotation.Retention;
@@ -229,7 +229,7 @@
     public void showSearchEnginePromoIfNeeded(
             final Activity activity, final @Nullable Callback<Boolean> onSearchEngineFinalized) {
         assert LibraryLoader.getInstance().isInitialized();
-        TemplateUrlService.getInstance().runWhenLoaded(new Runnable() {
+        TemplateUrlServiceFactory.get().runWhenLoaded(new Runnable() {
             @Override
             public void run() {
                 handleSearchEnginePromoWithTemplateUrlsLoaded(activity, onSearchEngineFinalized);
@@ -239,7 +239,7 @@
 
     private void handleSearchEnginePromoWithTemplateUrlsLoaded(
             final Activity activity, final @Nullable Callback<Boolean> onSearchEngineFinalized) {
-        assert TemplateUrlService.getInstance().isLoaded();
+        assert TemplateUrlServiceFactory.get().isLoaded();
 
         final Callback<Boolean> finalizeInternalCallback = new Callback<Boolean>() {
             @Override
@@ -257,7 +257,7 @@
                 if (onSearchEngineFinalized != null) onSearchEngineFinalized.onResult(result);
             }
         };
-        if (TemplateUrlService.getInstance().isDefaultSearchManaged()
+        if (TemplateUrlServiceFactory.get().isDefaultSearchManaged()
                 || ApiCompatibilityUtils.isDemoUser(activity)) {
             finalizeInternalCallback.onResult(true);
             return;
@@ -411,7 +411,7 @@
      */
     protected void onUserSearchEngineChoiceFromPromoDialog(
             @SearchEnginePromoType int type, List<String> keywords, String keyword) {
-        TemplateUrlService.getInstance().setSearchEngine(keyword);
+        TemplateUrlServiceFactory.get().setSearchEngine(keyword);
         ContextUtils.getAppSharedPreferences()
                 .edit()
                 .putInt(KEY_SEARCH_ENGINE_PROMO_SHOW_STATE,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/LogoView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/LogoView.java
index 8d4cd6f..1a8be49e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/LogoView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/LogoView.java
@@ -29,7 +29,7 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ntp.LogoBridge.Logo;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.widget.LoadingView;
 
 import java.lang.ref.WeakReference;
@@ -303,7 +303,7 @@
      * @return The default logo.
      */
     private Bitmap getDefaultLogo() {
-        if (!TemplateUrlService.getInstance().isDefaultSearchEngineGoogle()) return null;
+        if (!TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle()) return null;
 
         Bitmap defaultLogo = sDefaultLogo == null ? null : sDefaultLogo.get();
         final int tint = ApiCompatibilityUtils.getColor(getResources(), R.color.google_logo_tint);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index b6707a3..cc53aec 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -38,8 +38,7 @@
 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 import org.chromium.chrome.browser.omnibox.LocationBarVoiceRecognitionHandler;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.suggestions.SuggestionsDependencyFactory;
 import org.chromium.chrome.browser.suggestions.SuggestionsEventReporter;
@@ -59,6 +58,7 @@
 import org.chromium.chrome.browser.util.UrlConstants;
 import org.chromium.chrome.browser.util.UrlUtilities;
 import org.chromium.chrome.browser.vr.VrModuleProvider;
+import org.chromium.components.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
 import org.chromium.content_public.browser.NavigationController;
 import org.chromium.content_public.browser.NavigationEntry;
 import org.chromium.content_public.common.BrowserControlsState;
@@ -307,7 +307,7 @@
         mBackgroundColor = ApiCompatibilityUtils.getColor(
                 activity.getResources(), R.color.modern_primary_color);
         mIsTablet = activity.isTablet();
-        TemplateUrlService.getInstance().addObserver(this);
+        TemplateUrlServiceFactory.get().addObserver(this);
 
         mTabObserver = new EmptyTabObserver() {
             @Override
@@ -374,7 +374,7 @@
 
         mNewTabPageView.initialize(mNewTabPageManager, mTab, mTileGroupDelegate,
                 mSearchProviderHasLogo,
-                TemplateUrlService.getInstance().isDefaultSearchEngineGoogle(),
+                TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle(),
                 getScrollPositionFromNavigationEntry(NAVIGATION_ENTRY_SCROLL_POSITION_KEY, mTab),
                 mConstructedTimeNs);
     }
@@ -467,13 +467,13 @@
     }
 
     private void updateSearchProviderHasLogo() {
-        mSearchProviderHasLogo = TemplateUrlService.getInstance().doesDefaultSearchEngineHaveLogo();
+        mSearchProviderHasLogo = TemplateUrlServiceFactory.doesDefaultSearchEngineHaveLogo();
     }
 
     private void onSearchEngineUpdated() {
         updateSearchProviderHasLogo();
         setSearchProviderInfoOnView(mSearchProviderHasLogo,
-                TemplateUrlService.getInstance().isDefaultSearchEngineGoogle());
+                TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle());
         mNewTabPageLayout.loadSearchProviderLogo();
     }
 
@@ -678,7 +678,7 @@
 
         mNewTabPageManager.onDestroy();
         mTileGroupDelegate.destroy();
-        TemplateUrlService.getInstance().removeObserver(this);
+        TemplateUrlServiceFactory.get().removeObserver(this);
         mTab.removeObserver(mTabObserver);
         mTabObserver = null;
         mFullscreenManager.removeListener(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 6a55c58..e1cba2dc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -50,7 +50,7 @@
 import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestionListEmbedder;
 import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
 import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
@@ -58,6 +58,7 @@
 import org.chromium.chrome.browser.toolbar.top.ToolbarActionModeCallback;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
 import org.chromium.chrome.browser.util.ColorUtils;
+import org.chromium.components.search_engines.TemplateUrlService;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.PageTransition;
@@ -476,13 +477,13 @@
 
         if (hasFocus && mToolbarDataProvider.hasTab() && !mToolbarDataProvider.isIncognito()) {
             if (mNativeInitialized
-                    && TemplateUrlService.getInstance().isDefaultSearchEngineGoogle()) {
+                    && TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle()) {
                 GeolocationHeader.primeLocationForGeoHeader();
             } else {
                 mDeferredNativeRunnables.add(new Runnable() {
                     @Override
                     public void run() {
-                        if (TemplateUrlService.getInstance().isDefaultSearchEngineGoogle()) {
+                        if (TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle()) {
                             GeolocationHeader.primeLocationForGeoHeader();
                         }
                     }
@@ -747,7 +748,7 @@
     public void performSearchQueryForTest(String query) {
         if (TextUtils.isEmpty(query)) return;
 
-        String queryUrl = TemplateUrlService.getInstance().getUrlForSearchQuery(query);
+        String queryUrl = TemplateUrlServiceFactory.get().getUrlForSearchQuery(query);
 
         if (!TextUtils.isEmpty(queryUrl)) {
             loadUrl(queryUrl, PageTransition.GENERATED, 0);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandler.java
index dd28aca3..7f4465c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandler.java
@@ -19,7 +19,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteController;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.chrome.browser.util.FeatureUtilities;
@@ -186,8 +186,7 @@
 
             RenderFrameHost renderFrameHost = webContents.getMainFrame();
             if (renderFrameHost == null) return;
-            if (TemplateUrlService.getInstance().isSearchResultsPageFromDefaultSearchProvider(
-                        url)) {
+            if (TemplateUrlServiceFactory.get().isSearchResultsPageFromDefaultSearchProvider(url)) {
                 renderFrameHost.notifyUserActivation();
             }
         }
@@ -256,7 +255,7 @@
 
             String url = AutocompleteController.nativeQualifyPartialURLQuery(topResultQuery);
             if (url == null) {
-                url = TemplateUrlService.getInstance().getUrlForVoiceSearchQuery(topResultQuery);
+                url = TemplateUrlServiceFactory.get().getUrlForVoiceSearchQuery(topResultQuery);
             }
 
             // Since voice was used, we need to let the frame know that there was a user gesture.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/VoiceSuggestionProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/VoiceSuggestionProvider.java
index a91b415..9e6d011 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/VoiceSuggestionProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/VoiceSuggestionProvider.java
@@ -11,7 +11,7 @@
 import org.chromium.chrome.browser.omnibox.MatchClassificationStyle;
 import org.chromium.chrome.browser.omnibox.OmniboxSuggestionType;
 import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion.MatchClassification;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -117,7 +117,7 @@
         if (doesVoiceResultHaveMatch(suggestions, result)) return;
         if (result.getConfidence() < confidenceThreshold && result.getConfidence() > 0) return;
         String voiceUrl =
-                TemplateUrlService.getInstance().getUrlForVoiceSearchQuery(result.getMatch());
+                TemplateUrlServiceFactory.get().getUrlForVoiceSearchQuery(result.getMatch());
         List<MatchClassification> classifications = new ArrayList<>();
         classifications.add(new MatchClassification(0, MatchClassificationStyle.NONE));
         suggestions.add(new OmniboxSuggestion(OmniboxSuggestionType.VOICE_SUGGEST, true, 0, 1,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
index 7a38275b..e3096f1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
@@ -24,11 +24,12 @@
 import org.chromium.chrome.browser.preferences.autofill_assistant.AutofillAssistantPreferences;
 import org.chromium.chrome.browser.preferences.datareduction.DataReductionPreferenceFragment;
 import org.chromium.chrome.browser.preferences.developer.DeveloperPreferences;
-import org.chromium.chrome.browser.search_engines.TemplateUrl;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.signin.SigninManager;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.browser.util.FeatureUtilities;
+import org.chromium.components.search_engines.TemplateUrl;
+import org.chromium.components.search_engines.TemplateUrlService;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -150,9 +151,9 @@
             getPreferenceScreen().removePreference(findPreference(PREF_NOTIFICATIONS));
         }
 
-        if (!TemplateUrlService.getInstance().isLoaded()) {
-            TemplateUrlService.getInstance().registerLoadListener(this);
-            TemplateUrlService.getInstance().load();
+        if (!TemplateUrlServiceFactory.get().isLoaded()) {
+            TemplateUrlServiceFactory.get().registerLoadListener(this);
+            TemplateUrlServiceFactory.get().load();
         }
 
         // This checks whether the flag for Downloads Preferences is enabled.
@@ -245,7 +246,7 @@
     }
 
     private void updateSearchEnginePreference() {
-        if (!TemplateUrlService.getInstance().isLoaded()) {
+        if (!TemplateUrlServiceFactory.get().isLoaded()) {
             ChromeBasePreference searchEnginePref =
                     (ChromeBasePreference) findPreference(PREF_SEARCH_ENGINE);
             searchEnginePref.setEnabled(false);
@@ -254,7 +255,7 @@
 
         String defaultSearchEngineName = null;
         TemplateUrl dseTemplateUrl =
-                TemplateUrlService.getInstance().getDefaultSearchEngineTemplateUrl();
+                TemplateUrlServiceFactory.get().getDefaultSearchEngineTemplateUrl();
         if (dseTemplateUrl != null) defaultSearchEngineName = dseTemplateUrl.getShortName();
 
         Preference searchEnginePreference = findPreference(PREF_SEARCH_ENGINE);
@@ -300,7 +301,7 @@
     // TemplateUrlService.LoadListener implementation.
     @Override
     public void onTemplateUrlServiceLoaded() {
-        TemplateUrlService.getInstance().unregisterLoadListener(this);
+        TemplateUrlServiceFactory.get().unregisterLoadListener(this);
         updateSearchEnginePreference();
     }
 
@@ -322,7 +323,7 @@
                     return DataReductionProxySettings.getInstance().isDataReductionProxyManaged();
                 }
                 if (PREF_SEARCH_ENGINE.equals(preference.getKey())) {
-                    return TemplateUrlService.getInstance().isDefaultSearchManaged();
+                    return TemplateUrlServiceFactory.get().isDefaultSearchManaged();
                 }
                 return false;
             }
@@ -335,7 +336,7 @@
                             && !settings.isDataReductionProxyEnabled();
                 }
                 if (PREF_SEARCH_ENGINE.equals(preference.getKey())) {
-                    return TemplateUrlService.getInstance().isDefaultSearchManaged();
+                    return TemplateUrlServiceFactory.get().isDefaultSearchManaged();
                 }
                 return isPreferenceControlledByPolicy(preference)
                         || isPreferenceControlledByCustodian(preference);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
index a36c2ae..9695aaa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
@@ -17,7 +17,7 @@
 import org.chromium.chrome.browser.download.DownloadPromptStatus;
 import org.chromium.chrome.browser.preferences.languages.LanguageItem;
 import org.chromium.chrome.browser.preferences.website.ContentSettingException;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -100,7 +100,7 @@
             // TODO(wnwen): Check while refactoring TemplateUrlService whether this belongs here.
             // This is necessary as far as ensuring that TemplateUrlService is loaded at some point.
             // Put initialization here to make instantiation in unit tests easier.
-            TemplateUrlService.getInstance().load();
+            TemplateUrlServiceFactory.get().load();
         }
         return sInstance;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java
index b3ea22b5..663c943 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java
@@ -35,9 +35,10 @@
 import org.chromium.chrome.browser.preferences.website.PermissionInfo;
 import org.chromium.chrome.browser.preferences.website.SingleWebsitePreferences;
 import org.chromium.chrome.browser.preferences.website.WebsitePreferenceBridge;
-import org.chromium.chrome.browser.search_engines.TemplateUrl;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.components.location.LocationUtils;
+import org.chromium.components.search_engines.TemplateUrl;
+import org.chromium.components.search_engines.TemplateUrlService;
 import org.chromium.ui.text.SpanApplier;
 import org.chromium.ui.text.SpanApplier.SpanInfo;
 
@@ -118,7 +119,7 @@
      */
     public void start() {
         refreshData();
-        TemplateUrlService.getInstance().addObserver(this);
+        TemplateUrlServiceFactory.get().addObserver(this);
     }
 
     /**
@@ -126,11 +127,11 @@
      */
     public void stop() {
         if (mHasLoadObserver) {
-            TemplateUrlService.getInstance().unregisterLoadListener(this);
+            TemplateUrlServiceFactory.get().unregisterLoadListener(this);
             mHasLoadObserver = false;
         }
 
-        TemplateUrlService.getInstance().removeObserver(this);
+        TemplateUrlServiceFactory.get().removeObserver(this);
     }
 
     @VisibleForTesting
@@ -152,7 +153,7 @@
      * Initialize the search engine list.
      */
     private void refreshData() {
-        TemplateUrlService templateUrlService = TemplateUrlService.getInstance();
+        TemplateUrlService templateUrlService = TemplateUrlServiceFactory.get();
         if (!templateUrlService.isLoaded()) {
             mHasLoadObserver = true;
             templateUrlService.registerLoadListener(this);
@@ -410,8 +411,9 @@
 
         TextView link = (TextView) view.findViewById(R.id.location_permission);
         link.setVisibility(View.GONE);
-        if (TemplateUrlService.getInstance().getSearchEngineUrlFromTemplateUrl(
-                templateUrl.getKeyword()) == null) {
+        if (TemplateUrlServiceFactory.get().getSearchEngineUrlFromTemplateUrl(
+                    templateUrl.getKeyword())
+                == null) {
             Log.e(TAG, "Invalid template URL found: %s", templateUrl);
             assert false;
         } else if (selected) {
@@ -425,7 +427,7 @@
 
     @Override
     public void onTemplateUrlServiceLoaded() {
-        TemplateUrlService.getInstance().unregisterLoadListener(this);
+        TemplateUrlServiceFactory.get().unregisterLoadListener(this);
         mHasLoadObserver = false;
         refreshData();
     }
@@ -451,7 +453,7 @@
         mSelectedSearchEnginePosition = position;
 
         String keyword = toKeyword(mSelectedSearchEnginePosition);
-        TemplateUrlService.getInstance().setSearchEngine(keyword);
+        TemplateUrlServiceFactory.get().setSearchEngine(keyword);
 
         // If the user has manually set the default search engine, disable auto switching.
         boolean manualSwitch = mSelectedSearchEnginePosition != mInitialEnginePosition;
@@ -465,7 +467,7 @@
 
     private void onPermissionsLinkClicked() {
         mIsLocationPermissionChanged = true;
-        String url = TemplateUrlService.getInstance().getSearchEngineUrlFromTemplateUrl(
+        String url = TemplateUrlServiceFactory.get().getSearchEngineUrlFromTemplateUrl(
                 toKeyword(mSelectedSearchEnginePosition));
         int linkBeingShown = getPermissionsLinkMessage(url);
         assert linkBeingShown != 0;
@@ -486,7 +488,7 @@
             return "";
         }
 
-        String url = TemplateUrlService.getInstance().getSearchEngineUrlFromTemplateUrl(
+        String url = TemplateUrlServiceFactory.get().getSearchEngineUrlFromTemplateUrl(
                 templateUrl.getKeyword());
         if (url == null) {
             Log.e(TAG, "Invalid template URL found: %s", templateUrl);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java
index ed359bef..024ddb99 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java
@@ -19,6 +19,8 @@
 import org.chromium.chrome.browser.snackbar.Snackbar;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController;
+import org.chromium.components.search_engines.TemplateUrl;
+import org.chromium.components.search_engines.TemplateUrlService;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -192,7 +194,7 @@
 
     @SearchEngineType
     private static int getDefaultSearchEngineType() {
-        TemplateUrlService templateUrlService = TemplateUrlService.getInstance();
+        TemplateUrlService templateUrlService = TemplateUrlServiceFactory.get();
         TemplateUrl currentSearchEngine = templateUrlService.getDefaultSearchEngineTemplateUrl();
         if (currentSearchEngine == null) return SearchEngineType.SEARCH_ENGINE_UNKNOWN;
         return templateUrlService.getSearchEngineTypeFromTemplateUrl(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceFactory.java
new file mode 100644
index 0000000..f6b0884
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceFactory.java
@@ -0,0 +1,45 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.search_engines;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.components.search_engines.TemplateUrlService;
+
+/**
+ * This factory links the native TemplateURLService for the current Profile to create and hold a
+ * {@link TemplateUrlService} singleton.
+ */
+public class TemplateUrlServiceFactory {
+    private static TemplateUrlService sTemplateUrlService;
+
+    private TemplateUrlServiceFactory() {}
+
+    /**
+     * @return The singleton instance of {@link TemplateUrlService}, creating it if necessary.
+     */
+    public static TemplateUrlService get() {
+        ThreadUtils.assertOnUiThread();
+        if (sTemplateUrlService == null) {
+            sTemplateUrlService = nativeGetTemplateUrlService();
+        }
+        return sTemplateUrlService;
+    }
+
+    @VisibleForTesting
+    static void setInstanceForTesting(TemplateUrlService service) {
+        sTemplateUrlService = service;
+    }
+
+    /**
+     * TODO(crbug.com/968156): Move to TemplateUrlServiceHelper.
+     */
+    public static boolean doesDefaultSearchEngineHaveLogo() {
+        return nativeDoesDefaultSearchEngineHaveLogo();
+    }
+
+    private static native TemplateUrlService nativeGetTemplateUrlService();
+    private static native boolean nativeDoesDefaultSearchEngineHaveLogo();
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
index 4690468..9c1f308 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -34,6 +34,7 @@
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteController;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarManageable;
+import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabBuilder;
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
@@ -213,7 +214,10 @@
             }
 
             @Override
-            public void createBrowserControlsState(Tab tab) {}
+            public BrowserControlsVisibilityDelegate createBrowserControlsVisibilityDelegate(
+                    Tab tab) {
+                return null;
+            }
         };
         mTab.initialize(
                 WebContentsFactory.createWebContents(false, false), factory, false, null, false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProvider.java
index 591f72b..6e2163a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProvider.java
@@ -31,11 +31,12 @@
 import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer;
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.omnibox.UrlBarData;
-import org.chromium.chrome.browser.search_engines.TemplateUrl;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService.LoadListener;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.util.IntentUtils;
+import org.chromium.components.search_engines.TemplateUrl;
+import org.chromium.components.search_engines.TemplateUrlService;
+import org.chromium.components.search_engines.TemplateUrlService.LoadListener;
+import org.chromium.components.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
 
 /**
  * Widget that lets the user search using their default search engine.
@@ -91,7 +92,7 @@
             implements LoadListener, TemplateUrlServiceObserver {
         @Override
         public void onTemplateUrlServiceLoaded() {
-            TemplateUrlService.getInstance().unregisterLoadListener(this);
+            TemplateUrlServiceFactory.get().unregisterLoadListener(this);
             updateCachedEngineName();
         }
 
@@ -149,7 +150,7 @@
             if (sObserver != null) return;
             sObserver = new SearchWidgetTemplateUrlServiceObserver();
 
-            TemplateUrlService service = TemplateUrlService.getInstance();
+            TemplateUrlService service = TemplateUrlServiceFactory.get();
             service.registerLoadListener(sObserver);
             service.addObserver(sObserver);
             if (!service.isLoaded()) service.load();
@@ -305,7 +306,7 @@
 
         // Getting an instance of the TemplateUrlService requires that the native library be
         // loaded, but the TemplateUrlService also itself needs to be initialized.
-        TemplateUrlService service = TemplateUrlService.getInstance();
+        TemplateUrlService service = TemplateUrlServiceFactory.get();
         if (!service.isLoaded()) return;
 
         // Update the URL that we show for zero-suggest.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/ChromeSigninManagerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/ChromeSigninManagerDelegate.java
index fa1a4d9..660a2f8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/ChromeSigninManagerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/ChromeSigninManagerDelegate.java
@@ -4,17 +4,33 @@
 
 package org.chromium.chrome.browser.signin;
 
+import android.accounts.Account;
 import android.app.Activity;
 import android.content.Context;
 
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.annotations.JCaller;
 import org.chromium.chrome.browser.externalauth.ExternalAuthUtils;
 import org.chromium.chrome.browser.externalauth.UserRecoverableErrorHandler;
+import org.chromium.components.sync.AndroidSyncSettings;
 
 /**
  * This implementation of {@link SigninManagerDelegate} provides {@link SigninManager} access to
  * //chrome/browser level dependencies.
  */
 public class ChromeSigninManagerDelegate implements SigninManagerDelegate {
+    private final AndroidSyncSettings mAndroidSyncSettings;
+
+    public ChromeSigninManagerDelegate() {
+        this(AndroidSyncSettings.get());
+    }
+
+    @VisibleForTesting
+    ChromeSigninManagerDelegate(AndroidSyncSettings androidSyncSettings) {
+        assert androidSyncSettings != null;
+        mAndroidSyncSettings = androidSyncSettings;
+    }
+
     @Override
     public void handleGooglePlayServicesUnavailability(Activity activity, boolean cancelable) {
         UserRecoverableErrorHandler errorHandler = activity != null
@@ -27,4 +43,38 @@
     public boolean isGooglePlayServicesPresent(Context context) {
         return !ExternalAuthUtils.getInstance().isGooglePlayServicesMissing(context);
     }
+
+    @Override
+    public void fetchAndApplyCloudPolicy(@JCaller SigninManager signinManager,
+            long nativeSigninManagerAndroid, String username) {
+        SigninManagerJni.get().fetchAndApplyCloudPolicy(
+                signinManager, nativeSigninManagerAndroid, username);
+    }
+
+    @Override
+    public void stopApplyingCloudPolicy(
+            @JCaller SigninManager signinManager, long nativeSigninManagerAndroid) {
+        SigninManagerJni.get().abortSignIn(signinManager, nativeSigninManagerAndroid);
+    }
+
+    @Override
+    public void enableSync(Account account) {
+        // Cache the signed-in account name. This must be done after the native call, otherwise
+        // sync tries to start without being signed in natively and crashes.
+        mAndroidSyncSettings.updateAccount(account);
+        mAndroidSyncSettings.enableChromeSync();
+    }
+
+    @Override
+    public void disableSyncAndWipeData(@JCaller SigninManager signinManager,
+            long nativeSigninManagerAndroid, boolean isManaged, final Runnable wipeDataCallback) {
+        mAndroidSyncSettings.updateAccount(null);
+        if (isManaged) {
+            SigninManagerJni.get().wipeProfileData(
+                    signinManager, nativeSigninManagerAndroid, wipeDataCallback);
+        } else {
+            SigninManagerJni.get().wipeGoogleServiceWorkerCaches(
+                    signinManager, nativeSigninManagerAndroid, wipeDataCallback);
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
index 4972780..b52cf4b0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
@@ -32,7 +32,6 @@
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.AccountTrackerService;
 import org.chromium.components.signin.ChromeSigninController;
-import org.chromium.components.sync.AndroidSyncSettings;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 import java.util.ArrayList;
@@ -183,7 +182,6 @@
     private final Context mContext;
     private final SigninManagerDelegate mDelegate;
     private final AccountTrackerService mAccountTrackerService;
-    private final AndroidSyncSettings mAndroidSyncSettings;
     private final ObserverList<SignInStateObserver> mSignInStateObservers = new ObserverList<>();
     private final ObserverList<SignInAllowedObserver> mSignInAllowedObservers =
             new ObserverList<>();
@@ -221,29 +219,26 @@
     public static SigninManager get() {
         ThreadUtils.assertOnUiThread();
         if (sSigninManager == null) {
-            SigninManagerDelegate delegate = new ChromeSigninManagerDelegate();
-            sSigninManager = new SigninManager(delegate);
+            sSigninManager = new SigninManager();
         }
         return sSigninManager;
     }
 
-    private SigninManager(SigninManagerDelegate delegate) {
-        this(ContextUtils.getApplicationContext(), delegate,
-                IdentityServicesProvider.getAccountTrackerService(), AndroidSyncSettings.get());
+    private SigninManager() {
+        this(ContextUtils.getApplicationContext(), new ChromeSigninManagerDelegate(),
+                IdentityServicesProvider.getAccountTrackerService());
     }
 
     @VisibleForTesting
     SigninManager(Context context, SigninManagerDelegate delegate,
-            AccountTrackerService accountTrackerService, AndroidSyncSettings androidSyncSettings) {
+            AccountTrackerService accountTrackerService) {
         ThreadUtils.assertOnUiThread();
         assert context != null;
         assert delegate != null;
         assert accountTrackerService != null;
-        assert androidSyncSettings != null;
         mDelegate = delegate;
         mContext = context;
         mAccountTrackerService = accountTrackerService;
-        mAndroidSyncSettings = androidSyncSettings;
 
         mNativeSigninManagerAndroid = SigninManagerJni.get().init(this);
         mSigninAllowedByPolicy =
@@ -447,7 +442,7 @@
 
         Log.d(TAG, "Checking if account has policy management enabled");
         // This will call back to onPolicyFetchedBeforeSignIn.
-        SigninManagerJni.get().registerAndFetchPolicyBeforeSignIn(
+        mDelegate.fetchAndApplyCloudPolicy(
                 this, mNativeSigninManagerAndroid, mSignInState.mAccount.name);
     }
 
@@ -465,15 +460,13 @@
         // This method should be called at most once per sign-in flow.
         assert mSignInState != null;
 
-        // Tell the native side that sign-in has completed.
         SigninManagerJni.get().onSignInCompleted(
                 this, mNativeSigninManagerAndroid, mSignInState.mAccount.name);
 
         // Cache the signed-in account name. This must be done after the native call, otherwise
         // sync tries to start without being signed in natively and crashes.
         ChromeSigninController.get().setSignedInAccountName(mSignInState.mAccount.name);
-        mAndroidSyncSettings.updateAccount(mSignInState.mAccount);
-        mAndroidSyncSettings.enableChromeSync();
+        mDelegate.enableSync(mSignInState.mAccount);
 
         if (mSignInState.mCallback != null) {
             mSignInState.mCallback.onSignInComplete();
@@ -582,7 +575,8 @@
 
         Log.d(TAG, "Signing out, management domain: " + mSignOutState.mManagementDomain);
 
-        // User data will be wiped in resetAccountData(), called from onNativeSignOut().
+        // User data will be wiped in mDelegate.disableSyncAndWipeData(), called from
+        // onNativeSignOut().
         SigninManagerJni.get().signOut(this, mNativeSigninManagerAndroid, signoutSource);
     }
 
@@ -618,7 +612,7 @@
             signInState.mCallback.onSignInAborted();
         }
 
-        SigninManagerJni.get().abortSignIn(this, mNativeSigninManagerAndroid);
+        mDelegate.stopApplyingCloudPolicy(this, mNativeSigninManagerAndroid);
 
         Log.d(TAG, "Signin flow aborted.");
         notifySignInAllowedChanged();
@@ -639,48 +633,13 @@
 
         // Native sign-out must happen before resetting the account so data is deleted correctly.
         // http://crbug.com/589028
-        resetAccountData();
-    }
-
-    /**
-     * Called AFTER native sign-out is complete, this method clears various
-     * account and profile data associated with the previous signin.
-     */
-    void resetAccountData() {
-        // Should be set at beginning of sign-out flow.
-        assert mSignOutState != null;
-
         ChromeSigninController.get().setSignedInAccountName(null);
-        mAndroidSyncSettings.updateAccount(null);
-
-        if (mSignOutState.mManagementDomain != null) {
-            wipeProfileData();
-        } else {
-            wipeGoogleServiceWorkerCaches();
-        }
-
+        if (mSignOutState.mWipeDataHooks != null) mSignOutState.mWipeDataHooks.preWipeData();
+        mDelegate.disableSyncAndWipeData(this, mNativeSigninManagerAndroid,
+                mSignOutState.mManagementDomain != null, this::onProfileDataWiped);
         mAccountTrackerService.invalidateAccountSeedStatus(true);
     }
 
-    private void wipeProfileData() {
-        // Should be set at start of sign-out flow.
-        assert mSignOutState != null;
-
-        if (mSignOutState.mWipeDataHooks != null) mSignOutState.mWipeDataHooks.preWipeData();
-        // This will call back to onProfileDataWiped().
-        SigninManagerJni.get().wipeProfileData(this, mNativeSigninManagerAndroid);
-    }
-
-    private void wipeGoogleServiceWorkerCaches() {
-        // Should be set at start of sign-out flow.
-        assert mSignOutState != null;
-
-        if (mSignOutState.mWipeDataHooks != null) mSignOutState.mWipeDataHooks.preWipeData();
-        // This will call back to onProfileDataWiped().
-        SigninManagerJni.get().wipeGoogleServiceWorkerCaches(this, mNativeSigninManagerAndroid);
-    }
-
-    @CalledByNative
     @VisibleForTesting
     protected void onProfileDataWiped() {
         // Should be set at start of sign-out flow.
@@ -746,7 +705,7 @@
 
         boolean isForceSigninEnabled(@JCaller SigninManager self, long nativeSigninManagerAndroid);
 
-        void registerAndFetchPolicyBeforeSignIn(
+        void fetchAndApplyCloudPolicy(
                 @JCaller SigninManager self, long nativeSigninManagerAndroid, String username);
 
         void abortSignIn(@JCaller SigninManager self, long nativeSigninManagerAndroid);
@@ -759,10 +718,11 @@
 
         String getManagementDomain(@JCaller SigninManager self, long nativeSigninManagerAndroid);
 
-        void wipeProfileData(@JCaller SigninManager self, long nativeSigninManagerAndroid);
+        void wipeProfileData(
+                @JCaller SigninManager self, long nativeSigninManagerAndroid, Runnable callback);
 
         void wipeGoogleServiceWorkerCaches(
-                @JCaller SigninManager self, long nativeSigninManagerAndroid);
+                @JCaller SigninManager self, long nativeSigninManagerAndroid, Runnable callback);
 
         void clearLastSignedInUser(@JCaller SigninManager self, long nativeSigninManagerAndroid);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerDelegate.java
index 5cf548a..eb32668 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerDelegate.java
@@ -4,9 +4,12 @@
 
 package org.chromium.chrome.browser.signin;
 
+import android.accounts.Account;
 import android.app.Activity;
 import android.content.Context;
 
+import org.chromium.base.annotations.JCaller;
+
 /**
  * Interface providing SigninManager access to dependencies that are not part of the SignIn
  * component. This interface interacts with //chrome features such as Policy, Sync, data wiping,
@@ -25,4 +28,41 @@
      * @return Whether the device has Google Play Services.
      */
     public boolean isGooglePlayServicesPresent(Context context);
+
+    /**
+     * Interact with the UserPolicySigninService to retrieve the user policy.
+     * @param signinManager a reference on SigninManager used for the native calls
+     * @param nativeSigninManagerAndroid a reference on the native SigninManager used for native
+     *                                   calls
+     * @param username (email) of the user signing in.
+     */
+    public void fetchAndApplyCloudPolicy(
+            @JCaller SigninManager signinManager, long nativeSigninManagerAndroid, String username);
+
+    /**
+     * Perform the required cloud policy cleanup when a signin is aborted.
+     * @param signinManager a reference on SigninManager used for the native calls
+     * @param nativeSigninManagerAndroid a reference on the native SigninManager used for native
+     *                                   calls
+     */
+    public void stopApplyingCloudPolicy(
+            @JCaller SigninManager signinManager, long nativeSigninManagerAndroid);
+
+    /**
+     * Called AFTER native sign-in is complete, enabling Sync.
+     * @param account to be used by sync
+     */
+    public void enableSync(Account account);
+
+    /**
+     * Called AFTER native sign-out is complete, this method clears various
+     * account and profile data associated with the previous signin and aborts sync.
+     * @param signinManager a reference on SigninManager used for the native calls
+     * @param nativeSigninManagerAndroid a reference on the native SigninManager used for native
+     *                                   calls
+     * @param isManaged if the account is managed, which triggers a different cleanup flow
+     * @param wipeDataCallback to be called once profile data cleanup is complete
+     */
+    public void disableSyncAndWipeData(@JCaller SigninManager signinManager,
+            long nativeSigninManagerAndroid, boolean isManaged, Runnable wipeDataCallback);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 3588d08b..21186548 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -867,10 +867,8 @@
 
             initializeNative();
 
-            RevenueStats.getInstance().tabCreated(this);
-
             mDelegateFactory = delegateFactory;
-            mDelegateFactory.createBrowserControlsState(this);
+            RevenueStats.getInstance().tabCreated(this);
 
             // If there is a frozen WebContents state or a pending lazy load, don't create a new
             // WebContents.
@@ -1009,7 +1007,6 @@
         // Update the delegate factory, then recreate and propagate all delegates.
         mDelegateFactory = tabDelegateFactory;
         mWebContentsDelegate = mDelegateFactory.createWebContentsDelegate(this);
-        mDelegateFactory.createBrowserControlsState(this);
 
         // Reload the NativePage (if any), since the old NativePage has a reference to the old
         // activity.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBrowserControlsState.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBrowserControlsState.java
index ac4062b..d5219de5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBrowserControlsState.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBrowserControlsState.java
@@ -13,23 +13,21 @@
 import org.chromium.content_public.common.BrowserControlsState;
 
 /**
- * Manages the state of tab browser controls. Instantiation is done by
- * {@link TabDelegateFactory#createBrowserControlsState()}.
+ * Manages the state of tab browser controls.
  */
 public class TabBrowserControlsState extends TabWebContentsUserData implements ImeEventObserver {
     private static final Class<TabBrowserControlsState> USER_DATA_KEY =
             TabBrowserControlsState.class;
 
     private final Tab mTab;
-    private final BrowserControlsVisibilityDelegate mVisibilityDelegate;
-    private final long mNativeTabBrowserControlsState;
+    private long mNativeTabBrowserControlsState; // Lazily initialized in |update|
+    private BrowserControlsVisibilityDelegate mVisibilityDelegate;
 
     /** The current browser controls constraints. -1 if not set. */
     private @BrowserControlsState int mConstraints = -1;
 
-    public static void create(Tab tab, BrowserControlsVisibilityDelegate delegate) {
-        tab.getUserDataHost().setUserData(
-                USER_DATA_KEY, new TabBrowserControlsState(tab, delegate));
+    public static void createForTab(Tab tab) {
+        tab.getUserDataHost().setUserData(USER_DATA_KEY, new TabBrowserControlsState(tab));
     }
 
     public static TabBrowserControlsState get(Tab tab) {
@@ -74,11 +72,9 @@
     }
 
     /** Constructor */
-    private TabBrowserControlsState(Tab tab, BrowserControlsVisibilityDelegate delegate) {
+    private TabBrowserControlsState(Tab tab) {
         super(tab);
         mTab = tab;
-        mVisibilityDelegate = delegate;
-        mNativeTabBrowserControlsState = nativeInit();
         mTab.addObserver(new EmptyTabObserver() {
             @Override
             public void onSSLStateUpdated(Tab tab) {
@@ -86,6 +82,20 @@
             }
 
             @Override
+            public void onInitialized(Tab tab, TabState tabState) {
+                mVisibilityDelegate =
+                        tab.getDelegateFactory().createBrowserControlsVisibilityDelegate(tab);
+            }
+
+            @Override
+            public void onActivityAttachmentChanged(Tab tab, boolean isAttached) {
+                if (isAttached) {
+                    mVisibilityDelegate =
+                            tab.getDelegateFactory().createBrowserControlsVisibilityDelegate(tab);
+                }
+            }
+
+            @Override
             public void onRendererResponsiveStateChanged(Tab tab, boolean isResponsive) {
                 if (mTab.isHidden()) return;
                 if (isResponsive) {
@@ -109,7 +119,7 @@
 
     @Override
     public void destroyInternal() {
-        nativeOnDestroyed(mNativeTabBrowserControlsState);
+        if (mNativeTabBrowserControlsState != 0) nativeOnDestroyed(mNativeTabBrowserControlsState);
     }
 
     @Override
@@ -156,10 +166,9 @@
                         && current == BrowserControlsState.HIDDEN)) {
             return;
         }
-        if (mNativeTabBrowserControlsState != 0) {
-            nativeUpdateState(mNativeTabBrowserControlsState, mTab.getWebContents(), constraints,
-                    current, animate);
-        }
+        if (mNativeTabBrowserControlsState == 0) mNativeTabBrowserControlsState = nativeInit();
+        nativeUpdateState(mNativeTabBrowserControlsState, mTab.getWebContents(), constraints,
+                current, animate);
         if (constraints == mConstraints) return;
 
         mConstraints = constraints;
@@ -173,14 +182,15 @@
      * @return Whether hiding browser controls is enabled or not.
      */
     private boolean canAutoHide() {
-        return mVisibilityDelegate.canAutoHideBrowserControls();
+        return mVisibilityDelegate != null ? mVisibilityDelegate.canAutoHideBrowserControls()
+                                           : false;
     }
 
     /**
      * @return Whether showing browser controls is enabled or not.
      */
     public boolean canShow() {
-        return mVisibilityDelegate.canShowBrowserControls();
+        return mVisibilityDelegate != null ? mVisibilityDelegate.canShowBrowserControls() : false;
     }
 
     @BrowserControlsState
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java
index 6d81f42..d7d225db 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java
@@ -45,5 +45,5 @@
      * Creates the {@link BrowserControlsVisibilityDelegate} the tab will be initialized with.
      * @param tab The associated {@link Tab}.
      */
-    void createBrowserControlsState(Tab tab);
+    BrowserControlsVisibilityDelegate createBrowserControlsVisibilityDelegate(Tab tab);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabHelpers.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabHelpers.java
index 3fa0fea..e007bf2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabHelpers.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabHelpers.java
@@ -43,6 +43,7 @@
         }
         MediaSessionTabHelper.createForTab(tab);
         TaskTabHelper.createForTab(tab, parentTab);
+        TabBrowserControlsState.createForTab(tab);
 
         // TODO(jinsukkim): Do this by having something observe new tab creation.
         if (tab.isIncognito()) CipherFactory.getInstance().triggerKeyGeneration();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java
index dad01cb..92ee0c0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java
@@ -10,7 +10,6 @@
 
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.device.DeviceClassManager;
-import org.chromium.chrome.browser.fullscreen.FullscreenManager;
 import org.chromium.chrome.browser.modaldialog.TabModalPresenter;
 import org.chromium.chrome.browser.tab.Tab.TabHidingType;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
@@ -134,6 +133,11 @@
     }
 
     @Override
+    public boolean canShowBrowserControls() {
+        return true;
+    }
+
+    @Override
     public boolean canAutoHideBrowserControls() {
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.DONT_AUTO_HIDE_BROWSER_CONTROLS)
                 && mTab.getActivity() != null && mTab.getActivity().getToolbarManager() != null
@@ -167,12 +171,6 @@
         return enableHidingBrowserControls;
     }
 
-    @Override
-    public boolean canShowBrowserControls() {
-        FullscreenManager manager = FullscreenManager.from(mTab);
-        return manager != null ? !manager.getPersistentFullscreenMode() : true;
-    }
-
     /**
      * Disables the logic that prevents hiding the top controls during page load for testing.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/TabDelegateFactoryImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/TabDelegateFactoryImpl.java
index 4c207de..af9b55c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/TabDelegateFactoryImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/TabDelegateFactoryImpl.java
@@ -8,8 +8,8 @@
 import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator;
 import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator;
 import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler;
+import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabBrowserControlsState;
 import org.chromium.chrome.browser.tab.TabContextMenuItemDelegate;
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
 import org.chromium.chrome.browser.tab.TabStateBrowserControlsVisibilityDelegate;
@@ -47,7 +47,7 @@
     }
 
     @Override
-    public void createBrowserControlsState(Tab tab) {
-        TabBrowserControlsState.create(tab, new TabStateBrowserControlsVisibilityDelegate(tab));
+    public BrowserControlsVisibilityDelegate createBrowserControlsVisibilityDelegate(Tab tab) {
+        return new TabStateBrowserControlsVisibilityDelegate(tab);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 80376ec..c933f62 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -69,9 +69,7 @@
 import org.chromium.chrome.browser.previews.PreviewsAndroidBridge;
 import org.chromium.chrome.browser.previews.PreviewsUma;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.search_engines.TemplateUrl;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.SadTab;
 import org.chromium.chrome.browser.tab.Tab;
@@ -109,6 +107,9 @@
 import org.chromium.components.feature_engagement.EventConstants;
 import org.chromium.components.feature_engagement.FeatureConstants;
 import org.chromium.components.feature_engagement.Tracker;
+import org.chromium.components.search_engines.TemplateUrl;
+import org.chromium.components.search_engines.TemplateUrlService;
+import org.chromium.components.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.NavigationController;
 import org.chromium.content_public.browser.NavigationEntry;
@@ -1196,7 +1197,7 @@
             mBookmarkBridge = null;
         }
         if (mTemplateUrlObserver != null) {
-            TemplateUrlService.getInstance().removeObserver(mTemplateUrlObserver);
+            TemplateUrlServiceFactory.get().removeObserver(mTemplateUrlObserver);
             mTemplateUrlObserver = null;
         }
         if (mOverviewModeBehavior != null) {
@@ -1275,7 +1276,7 @@
     }
 
     private void registerTemplateUrlObserver() {
-        final TemplateUrlService templateUrlService = TemplateUrlService.getInstance();
+        final TemplateUrlService templateUrlService = TemplateUrlServiceFactory.get();
         assert mTemplateUrlObserver == null;
         mTemplateUrlObserver = new TemplateUrlServiceObserver() {
             private TemplateUrl mSearchEngine =
@@ -1299,7 +1300,7 @@
     private void onNativeLibraryReady() {
         mNativeLibraryReady = true;
 
-        final TemplateUrlService templateUrlService = TemplateUrlService.getInstance();
+        final TemplateUrlService templateUrlService = TemplateUrlServiceFactory.get();
         TemplateUrlService.LoadListener mTemplateServiceLoadListener =
                 new TemplateUrlService.LoadListener() {
                     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/upgrade/PackageReplacedBroadcastReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/upgrade/PackageReplacedBroadcastReceiver.java
index a188387..3ba8f0f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/upgrade/PackageReplacedBroadcastReceiver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/upgrade/PackageReplacedBroadcastReceiver.java
@@ -10,6 +10,7 @@
 
 import org.chromium.base.task.AsyncTask;
 import org.chromium.base.task.BackgroundOnlyAsyncTask;
+import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantModuleEntryProvider;
 import org.chromium.chrome.browser.notifications.channels.ChannelsUpdater;
 import org.chromium.chrome.browser.vr.VrModuleProvider;
 
@@ -33,6 +34,7 @@
         if (!Intent.ACTION_MY_PACKAGE_REPLACED.equals(intent.getAction())) return;
         updateChannelsIfNecessary();
         VrModuleProvider.maybeRequestModuleIfDaydreamReady();
+        AutofillAssistantModuleEntryProvider.maybeInstallDeferred();
     }
 
     private void updateChannelsIfNecessary() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDelegateFactory.java
index 241cc89..c3e349b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDelegateFactory.java
@@ -14,8 +14,8 @@
 import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator;
 import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator;
 import org.chromium.chrome.browser.fullscreen.ComposedBrowserControlsVisibilityDelegate;
+import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabBrowserControlsState;
 import org.chromium.chrome.browser.tab.TabContextMenuItemDelegate;
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
 import org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroid;
@@ -109,12 +109,11 @@
     }
 
     @Override
-    public void createBrowserControlsState(Tab tab) {
-        TabBrowserControlsState.create(tab,
-                new ComposedBrowserControlsVisibilityDelegate(
-                        new WebappBrowserControlsDelegate(mActivity, tab),
-                        // Ensures browser controls hiding is delayed after activity start.
-                        mActivity.getFullscreenManager().getBrowserVisibilityDelegate()));
+    public BrowserControlsVisibilityDelegate createBrowserControlsVisibilityDelegate(Tab tab) {
+        return new ComposedBrowserControlsVisibilityDelegate(
+                new WebappBrowserControlsDelegate(mActivity, tab),
+                // Ensures browser controls hiding is delayed after activity start.
+                mActivity.getFullscreenManager().getBrowserVisibilityDelegate());
     }
 
     @Override
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 5c7b8df..038f8973 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2791,6 +2791,25 @@
         Choose another account
       </message>
 
+      <!-- Sync confirmation dialog -->
+      <!-- TODO(https://crbug.com/846376): These strings are only used by pre-Unified Consent sync confirmation dialog. Remove them once Unified Consent is enabled by default. -->
+      <!-- "Chrome sync" is the Google Cloud Based service used for sync. Thus this string resource is set to "Chrome sync" even for Chromium builds. -->
+      <message name="IDS_SYNC_CONFIRMATION_CHROME_SYNC_TITLE" desc="Title of the chrome sync section of the sync confirmation dialog in the tab modal signin flow">
+        Chrome Sync
+      </message>
+      <message name="IDS_SYNC_CONFIRMATION_CHROME_SYNC_MESSAGE" desc="Body of the chrome sync section of the sync confirmation dialog in the tab modal signin flow">
+        Your bookmarks, history, passwords, and other settings will be synced to your Google Account so you can use them on all your devices
+      </message>
+      <message name="IDS_SYNC_CONFIRMATION_PERSONALIZE_SERVICES_TITLE" desc="Title of the personalize services section of the sync confirmation dialog in the tab modal signin flow">
+        Personalize Google services
+      </message>
+      <message name="IDS_SYNC_CONFIRMATION_PERSONALIZE_SERVICES_BODY" desc="Body of the personalize services section of the sync confirmation dialog in the tab modal signin flow">
+        Google may use your browsing history to personalize Search, ads, and other Google services
+      </message>
+      <message name="IDS_SYNC_CONFIRMATION_PERSONALIZE_SERVICES_BODY_CHILD_ACCOUNT" desc="Body of the personalize services section of the sync confirmation dialog in the tab modal signin flow for child accounts">
+        Google may use your browsing history to personalize Search and other Google services
+      </message>
+
       <!-- Messages for remote media playback (casting) -->
       <message name="IDS_ACCESSIBILITY_PLAY" desc="The play button that starts playing the media.">
         Play
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
index 7eb8a123..88189c8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
@@ -31,10 +31,10 @@
 import org.chromium.chrome.browser.locale.DefaultSearchEngineDialogHelperUtils;
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.locale.LocaleManager.SearchEnginePromoType;
-import org.chromium.chrome.browser.search_engines.TemplateUrl;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.MultiActivityTestRule;
+import org.chromium.components.search_engines.TemplateUrl;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
@@ -162,7 +162,7 @@
 
             @Override
             public List<TemplateUrl> getSearchEnginesForPromoDialog(int promoType) {
-                return TemplateUrlService.getInstance().getTemplateUrls();
+                return TemplateUrlServiceFactory.get().getTemplateUrls();
             }
         };
         LocaleManager.setInstanceForTest(mockManager);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelperTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelperTest.java
index 924ad5d..9a4b09a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelperTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelperTest.java
@@ -21,9 +21,9 @@
 
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.browser.locale.LocaleManager.SearchEnginePromoType;
-import org.chromium.chrome.browser.search_engines.TemplateUrl;
 import org.chromium.chrome.browser.widget.RadioButtonLayout;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.components.search_engines.TemplateUrl;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelperUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelperUtils.java
index 5f9583a4..d802f35 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelperUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelperUtils.java
@@ -11,7 +11,7 @@
 
 import org.chromium.base.task.PostTask;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
@@ -61,8 +61,9 @@
 
         // Confirm the engine was set appropriately.
         TestThreadUtils.runOnUiThreadBlocking(
-                () -> Assert.assertEquals("Search engine wasn't set",
-                                TemplateUrlService.getInstance()
+                ()
+                        -> Assert.assertEquals("Search engine wasn't set",
+                                TemplateUrlServiceFactory.get()
                                         .getDefaultSearchEngineTemplateUrl()
                                         .getKeyword(),
                                 sSelectedEngine));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEnginePromoDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEnginePromoDialogTest.java
index c1964c779..c7c0122b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEnginePromoDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEnginePromoDialogTest.java
@@ -19,11 +19,12 @@
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
-import org.chromium.chrome.browser.search_engines.TemplateUrl;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.searchwidget.SearchActivity;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.ActivityUtils;
+import org.chromium.components.search_engines.TemplateUrl;
+import org.chromium.components.search_engines.TemplateUrlService;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
@@ -49,7 +50,7 @@
                 LocaleManager mockManager = new LocaleManager() {
                     @Override
                     public List<TemplateUrl> getSearchEnginesForPromoDialog(int promoType) {
-                        return TemplateUrlService.getInstance().getTemplateUrls();
+                        return TemplateUrlServiceFactory.get().getTemplateUrls();
                     }
                 };
                 LocaleManager.setInstanceForTest(mockManager);
@@ -63,11 +64,12 @@
     public void testOnlyOneLiveDialog() throws Exception {
         final CallbackHelper templateUrlServiceInit = new CallbackHelper();
         TestThreadUtils.runOnUiThreadBlocking(
-                () -> TemplateUrlService.getInstance().registerLoadListener(
+                ()
+                        -> TemplateUrlServiceFactory.get().registerLoadListener(
                                 new TemplateUrlService.LoadListener() {
                                     @Override
                                     public void onTemplateUrlServiceLoaded() {
-                                        TemplateUrlService.getInstance().unregisterLoadListener(
+                                        TemplateUrlServiceFactory.get().unregisterLoadListener(
                                                 this);
                                         templateUrlServiceInit.notifyCalled();
                                     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/locale/LocaleManagerReferralTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/locale/LocaleManagerReferralTest.java
index 4f35c0f..c8aaa3fd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/locale/LocaleManagerReferralTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/locale/LocaleManagerReferralTest.java
@@ -20,7 +20,8 @@
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
+import org.chromium.components.search_engines.TemplateUrlService;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
 import java.util.Locale;
@@ -68,7 +69,7 @@
     public void testYandexReferralId() throws InterruptedException, TimeoutException {
         final CallbackHelper templateUrlServiceLoaded = new CallbackHelper();
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            TemplateUrlService templateUrlService = TemplateUrlService.getInstance();
+            TemplateUrlService templateUrlService = TemplateUrlServiceFactory.get();
             templateUrlService.registerLoadListener(new TemplateUrlService.LoadListener() {
                 @Override
                 public void onTemplateUrlServiceLoaded() {
@@ -82,21 +83,21 @@
         templateUrlServiceLoaded.waitForCallback("Template URLs never loaded", 0);
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            TemplateUrlService.getInstance().setSearchEngine("yandex.ru");
+            TemplateUrlServiceFactory.get().setSearchEngine("yandex.ru");
 
             // The initial param is empty, so ensure no clid param is passed.
-            String url = TemplateUrlService.getInstance().getUrlForSearchQuery("blah");
+            String url = TemplateUrlServiceFactory.get().getUrlForSearchQuery("blah");
             Assert.assertThat(url, not(containsString("&clid=")));
 
             // Initialize the value to something and verify it is included in the generated
             // URL.
             mYandexReferralId = "TESTING_IS_AWESOME";
-            url = TemplateUrlService.getInstance().getUrlForSearchQuery("blah");
+            url = TemplateUrlServiceFactory.get().getUrlForSearchQuery("blah");
             Assert.assertThat(url, containsString("&clid=TESTING_IS_AWESOME"));
 
             // Switch to google and ensure the clid param is no longer included.
-            TemplateUrlService.getInstance().setSearchEngine("google.com");
-            url = TemplateUrlService.getInstance().getUrlForSearchQuery("blah");
+            TemplateUrlServiceFactory.get().setSearchEngine("google.com");
+            url = TemplateUrlServiceFactory.get().getUrlForSearchQuery("blah");
             Assert.assertThat(url, not(containsString("&clid=")));
         });
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java
index ba6bd63..67a13f5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java
@@ -38,12 +38,13 @@
 import org.chromium.chrome.browser.preferences.website.ContentSettingValues;
 import org.chromium.chrome.browser.preferences.website.PermissionInfo;
 import org.chromium.chrome.browser.preferences.website.WebsitePreferenceBridge;
-import org.chromium.chrome.browser.search_engines.TemplateUrl;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService.LoadListener;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.test.ChromeBrowserTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.ActivityUtils;
+import org.chromium.components.search_engines.TemplateUrl;
+import org.chromium.components.search_engines.TemplateUrlService;
+import org.chromium.components.search_engines.TemplateUrlService.LoadListener;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
@@ -122,7 +123,7 @@
             // Simulate selecting the third search engine, ensure that TemplateUrlService is
             // updated, and location permission granted by default for the new engine.
             String keyword2 = pref.setValueForTesting("2");
-            TemplateUrlService templateUrlService = TemplateUrlService.getInstance();
+            TemplateUrlService templateUrlService = TemplateUrlServiceFactory.get();
             Assert.assertEquals(
                     keyword2, templateUrlService.getDefaultSearchEngineTemplateUrl().getKeyword());
             Assert.assertEquals(
@@ -136,7 +137,7 @@
                     url, url, ContentSettingValues.BLOCK, false);
             keyword3 = pref.setValueForTesting("3");
             Assert.assertEquals(keyword3,
-                    TemplateUrlService.getInstance()
+                    TemplateUrlServiceFactory.get()
                             .getDefaultSearchEngineTemplateUrl()
                             .getKeyword());
             Assert.assertEquals(
@@ -157,7 +158,7 @@
                     url, url, ContentSettingValues.ALLOW, false);
             keyword2 = pref.setValueForTesting("2");
             Assert.assertEquals(keyword2,
-                    TemplateUrlService.getInstance()
+                    TemplateUrlServiceFactory.get()
                             .getDefaultSearchEngineTemplateUrl()
                             .getKeyword());
 
@@ -187,7 +188,7 @@
         CriteriaHelper.pollUiThread(Criteria.equals(true, new Callable<Boolean>() {
             @Override
             public Boolean call() throws Exception {
-                return TemplateUrlService.getInstance().isDefaultSearchManaged();
+                return TemplateUrlServiceFactory.get().isDefaultSearchManaged();
             }
         }));
 
@@ -248,7 +249,7 @@
             int index = indexOfFirstHttpSearchEngine(pref);
             String keyword = pref.setValueForTesting(Integer.toString(index));
 
-            TemplateUrlService templateUrlService = TemplateUrlService.getInstance();
+            TemplateUrlService templateUrlService = TemplateUrlServiceFactory.get();
             Assert.assertEquals(
                     keyword, templateUrlService.getDefaultSearchEngineTemplateUrl().getKeyword());
             Assert.assertEquals(
@@ -257,7 +258,7 @@
     }
 
     private int indexOfFirstHttpSearchEngine(SearchEnginePreference pref) {
-        TemplateUrlService templateUrlService = TemplateUrlService.getInstance();
+        TemplateUrlService templateUrlService = TemplateUrlServiceFactory.get();
         List<TemplateUrl> urls = templateUrlService.getTemplateUrls();
         int index;
         for (index = 0; index < urls.size(); ++index) {
@@ -275,23 +276,23 @@
         // Make sure the template_url_service is loaded.
         final CallbackHelper onTemplateUrlServiceLoadedHelper = new CallbackHelper();
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            if (TemplateUrlService.getInstance().isLoaded()) {
+            if (TemplateUrlServiceFactory.get().isLoaded()) {
                 onTemplateUrlServiceLoadedHelper.notifyCalled();
             } else {
-                TemplateUrlService.getInstance().registerLoadListener(new LoadListener() {
+                TemplateUrlServiceFactory.get().registerLoadListener(new LoadListener() {
                     @Override
                     public void onTemplateUrlServiceLoaded() {
                         onTemplateUrlServiceLoadedHelper.notifyCalled();
                     }
                 });
-                TemplateUrlService.getInstance().load();
+                TemplateUrlServiceFactory.get().load();
             }
         });
         onTemplateUrlServiceLoadedHelper.waitForCallback(0);
     }
 
     private @ContentSettingValues int locationPermissionForSearchEngine(String keyword) {
-        String url = TemplateUrlService.getInstance().getSearchEngineUrlFromTemplateUrl(keyword);
+        String url = TemplateUrlServiceFactory.get().getSearchEngineUrlFromTemplateUrl(keyword);
         PermissionInfo locationSettings =
                 new PermissionInfo(PermissionInfo.Type.GEOLOCATION, url, null, false);
         @ContentSettingValues
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTest.java
index 67456ab..4461222 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTest.java
@@ -18,8 +18,10 @@
 import org.chromium.base.test.util.Restriction;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.browser.preferences.SearchEngineAdapter;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService.LoadListener;
 import org.chromium.chrome.browser.test.ChromeBrowserTestRule;
+import org.chromium.components.search_engines.TemplateUrl;
+import org.chromium.components.search_engines.TemplateUrlService;
+import org.chromium.components.search_engines.TemplateUrlService.LoadListener;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
@@ -61,7 +63,7 @@
         Assert.assertTrue(TestThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() {
             @Override
             public Boolean call() throws Exception {
-                return TemplateUrlService.getInstance().isLoaded();
+                return TemplateUrlServiceFactory.get().isLoaded();
             }
         }));
 
@@ -78,7 +80,7 @@
         String result = TestThreadUtils.runOnUiThreadBlocking(new Callable<String>() {
             @Override
             public String call() throws Exception {
-                return TemplateUrlService.getInstance().getUrlForContextualSearchQuery(
+                return TemplateUrlServiceFactory.get().getUrlForContextualSearchQuery(
                         query, alternative, prefetch, protocolVersion);
             }
         });
@@ -105,7 +107,7 @@
         Assert.assertTrue(TestThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() {
             @Override
             public Boolean call() throws Exception {
-                return TemplateUrlService.getInstance().isLoaded();
+                return TemplateUrlServiceFactory.get().isLoaded();
             }
         }));
 
@@ -113,7 +115,7 @@
         // again.
         final AtomicBoolean observerNotified = new AtomicBoolean(false);
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            TemplateUrlService service = TemplateUrlService.getInstance();
+            TemplateUrlService service = TemplateUrlServiceFactory.get();
             service.registerLoadListener(new LoadListener() {
                 @Override
                 public void onTemplateUrlServiceLoaded() {
@@ -287,7 +289,7 @@
                         new Callable<TemplateUrlService>() {
                             @Override
                             public TemplateUrlService call() {
-                                TemplateUrlService service = TemplateUrlService.getInstance();
+                                TemplateUrlService service = TemplateUrlServiceFactory.get();
                                 service.registerLoadListener(listener);
                                 service.load();
                                 return service;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTestUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTestUtils.java
deleted file mode 100644
index fa8e1b9..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTestUtils.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.search_engines;
-
-import org.chromium.base.test.util.CallbackHelper;
-import org.chromium.content_public.browser.test.util.TestThreadUtils;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
-/** Utility methods for tests that need to interact with the {@link TemplateUrlService}. */
-public class TemplateUrlServiceTestUtils {
-    /**
-     * Set the search engine.
-     * @param keyword The keyword of the selected search engine, e.g. "google.com".
-     */
-    public static void setSearchEngine(String keyword)
-            throws ExecutionException, InterruptedException, TimeoutException {
-        CallbackHelper callback = new CallbackHelper();
-        Callable<Void> setSearchEngineCallable = new Callable<Void>() {
-            @Override
-            public Void call() {
-                TemplateUrlService.getInstance().runWhenLoaded(() -> {
-                    TemplateUrlService.getInstance().setSearchEngine(keyword);
-                    callback.notifyCalled();
-                });
-                return null;
-            }
-        };
-        TestThreadUtils.runOnUiThreadBlocking(setSearchEngineCallable);
-        callback.waitForCallback("Failed to set search engine", 0);
-    }
-}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
index 41498af..2ce7671 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
@@ -38,14 +38,14 @@
 import org.chromium.chrome.browser.omnibox.UrlBar;
 import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion;
 import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion.MatchClassification;
-import org.chromium.chrome.browser.search_engines.TemplateUrl;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
+import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.searchwidget.SearchActivity.SearchActivityDelegate;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.MultiActivityTestRule;
 import org.chromium.chrome.test.util.ActivityUtils;
 import org.chromium.chrome.test.util.OmniboxTestUtils;
+import org.chromium.components.search_engines.TemplateUrl;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.KeyUtils;
@@ -108,7 +108,7 @@
 
                     @Override
                     public List<TemplateUrl> getSearchEnginesForPromoDialog(int promoType) {
-                        return TemplateUrlService.getInstance().getTemplateUrls();
+                        return TemplateUrlServiceFactory.get().getTemplateUrls();
                     }
                 });
                 super.showSearchEngineDialogIfNeeded(activity, onSearchEngineFinalized);
diff --git a/chrome/android/junit/DEPS b/chrome/android/junit/DEPS
index f0a295f..3c0e0e1 100644
--- a/chrome/android/junit/DEPS
+++ b/chrome/android/junit/DEPS
@@ -5,6 +5,7 @@
   "+components/bookmarks/common/android",
   "+components/offline_items_collection/core/android/java/src",
   "+components/payments/content/android/java/src/org/chromium/components/payments",
+  "+components/search_engines/android/java/src/org/chromium/components/search_engines",
   "+components/sync/android/java/src/org/chromium/components/sync",
   "+components/sync/test/android/javatests/src/org/chromium/components/sync/test/util",
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java
index f61b3848..671da9a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java
@@ -32,12 +32,12 @@
 import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator.ContextMenuMode;
 import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulatorTest.ShadowUrlUtilities;
 import org.chromium.chrome.browser.firstrun.FirstRunStatus;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService;
 import org.chromium.chrome.browser.util.UrlUtilities;
 import org.chromium.chrome.test.support.DisableHistogramsRule;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
+import org.chromium.components.search_engines.TemplateUrlService;
 import org.chromium.ui.base.MenuSourceType;
 
 import java.util.Arrays;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserStateBrowserControlsVisibilityDelegateTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserStateBrowserControlsVisibilityDelegateTest.java
index c95788f..0623291a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserStateBrowserControlsVisibilityDelegateTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/fullscreen/BrowserStateBrowserControlsVisibilityDelegateTest.java
@@ -38,7 +38,7 @@
     public void beforeTest() {
         MockitoAnnotations.initMocks(this);
 
-        mDelegate = new BrowserStateBrowserControlsVisibilityDelegate(mCallback);
+        mDelegate = new BrowserStateBrowserControlsVisibilityDelegate(mCallback, () -> true);
     }
 
     private void advanceTime(long amount) {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java
index 33efdaf..33c6383 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java
@@ -37,6 +37,8 @@
 import org.chromium.chrome.browser.snackbar.Snackbar;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.test.support.DisableHistogramsRule;
+import org.chromium.components.search_engines.TemplateUrl;
+import org.chromium.components.search_engines.TemplateUrlService;
 
 import java.util.HashMap;
 
@@ -74,7 +76,7 @@
         ShadowRecordHistogram.reset();
 
         // Sets up appropriate responses from Template URL service.
-        TemplateUrlService.setInstanceForTesting(mTemplateUrlService);
+        TemplateUrlServiceFactory.setInstanceForTesting(mTemplateUrlService);
         doReturn(TEST_ALTERNATIVE_ENGINE).when(mAlternativeSearchEngine).getKeyword();
         doReturn(SearchEngineType.SEARCH_ENGINE_DUCKDUCKGO)
                 .when(mTemplateUrlService)
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/signin/ChromeSigninManagerDelegateTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/signin/ChromeSigninManagerDelegateTest.java
new file mode 100644
index 0000000..c3f899b
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/signin/ChromeSigninManagerDelegateTest.java
@@ -0,0 +1,79 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.signin;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.JniMocker;
+import org.chromium.components.sync.AndroidSyncSettings;
+import org.chromium.components.sync.test.util.MockSyncContentResolverDelegate;
+
+/** Tests for {@link ChromeSigninManagerDelegate}. */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class ChromeSigninManagerDelegateTest {
+    @Rule
+    public JniMocker mocker = new JniMocker();
+
+    @Mock
+    SigninManager.Natives mNativeMock;
+
+    private ChromeSigninManagerDelegate mDelegate;
+
+    @Before
+    public void setUp() {
+        initMocks(this);
+
+        mocker.mock(SigninManagerJni.TEST_HOOKS, mNativeMock);
+
+        // SigninManager interacts with AndroidSyncSettings, but its not the focus
+        // of this test. Using MockSyncContentResolver reduces burden of test setup.
+        AndroidSyncSettings.overrideForTests(new MockSyncContentResolverDelegate(), null);
+
+        mDelegate = new ChromeSigninManagerDelegate(AndroidSyncSettings.get());
+    }
+    @Test
+    public void signOutWithManagedDomain() {
+        // Stub out various native calls. Some of these are verified as never called
+        // and those stubs simply allow that verification to catch any issues.
+        doNothing().when(mNativeMock).wipeProfileData(any(), anyLong(), any());
+        doNothing().when(mNativeMock).wipeGoogleServiceWorkerCaches(any(), anyLong(), any());
+
+        // Simulate call from SigninManager
+        mDelegate.disableSyncAndWipeData(null, 0L, true, null);
+
+        // Sign-out should only clear the profile when the user is managed.
+        verify(mNativeMock, times(1)).wipeProfileData(any(), anyLong(), any());
+        verify(mNativeMock, never()).wipeGoogleServiceWorkerCaches(any(), anyLong(), any());
+    }
+    @Test
+    public void signOutWithNullDomain() {
+        // Stub out various native calls. Some of these are verified as never called
+        // and those stubs simply allow that verification to catch any issues.
+        doNothing().when(mNativeMock).wipeProfileData(any(), anyLong(), any());
+        doNothing().when(mNativeMock).wipeGoogleServiceWorkerCaches(any(), anyLong(), any());
+
+        // Simulate call from SigninManager
+        mDelegate.disableSyncAndWipeData(null, 0L, false, null);
+
+        // Sign-out should only clear the service worker cache when the user is not managed.
+        verify(mNativeMock, never()).wipeProfileData(any(), anyLong(), any());
+        verify(mNativeMock, times(1)).wipeGoogleServiceWorkerCaches(any(), anyLong(), any());
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java
index e6ad5d76..de73d32 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java
@@ -35,8 +35,6 @@
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.AccountTrackerService;
-import org.chromium.components.sync.AndroidSyncSettings;
-import org.chromium.components.sync.test.util.MockSyncContentResolverDelegate;
 
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -65,14 +63,9 @@
         doReturn(true).when(mNativeMock).isSigninAllowedByPolicy(any(), anyLong());
 
         mAccountTrackerService = mock(AccountTrackerService.class);
-        AndroidSyncSettings androidSyncSettings = mock(AndroidSyncSettings.class);
 
-        mSigninManager = spy(new SigninManager(ContextUtils.getApplicationContext(), mDelegateMock,
-                mAccountTrackerService, androidSyncSettings));
-
-        // SigninManager interacts with AndroidSyncSettings, but its not the focus
-        // of this test. Using MockSyncContentResolver reduces burden of test setup.
-        AndroidSyncSettings.overrideForTests(new MockSyncContentResolverDelegate(), null);
+        mSigninManager = spy(new SigninManager(
+                ContextUtils.getApplicationContext(), mDelegateMock, mAccountTrackerService));
     }
 
     @Test
@@ -80,8 +73,7 @@
         // Stub out various native calls. Some of these are verified as never called
         // and those stubs simply allow that verification to catch any issues.
         doNothing().when(mNativeMock).signOut(any(), anyLong(), anyInt());
-        doNothing().when(mNativeMock).wipeProfileData(any(), anyLong());
-        doNothing().when(mNativeMock).wipeGoogleServiceWorkerCaches(any(), anyLong());
+        doNothing().when(mDelegateMock).disableSyncAndWipeData(any(), anyLong(), eq(true), any());
         // See verification of nativeWipeProfileData below.
         doReturn("TestDomain").when(mNativeMock).getManagementDomain(any(), anyLong());
 
@@ -91,15 +83,12 @@
         // nativeSignOut should be called *before* clearing any account data.
         // http://crbug.com/589028
         verify(mNativeMock, times(1)).signOut(any(), anyLong(), eq(SignoutReason.SIGNOUT_TEST));
-        verify(mNativeMock, never()).wipeGoogleServiceWorkerCaches(any(), anyLong());
-        verify(mNativeMock, never()).wipeProfileData(any(), anyLong());
+        verify(mDelegateMock, never()).disableSyncAndWipeData(any(), anyLong(), eq(true), any());
 
         // Simulate native callback to trigger clearing of account data.
         mSigninManager.onNativeSignOut();
 
-        // Sign-out should wipe all profile data when user has managed domain.
-        verify(mNativeMock, times(1)).wipeProfileData(any(), anyLong());
-        verify(mNativeMock, never()).wipeGoogleServiceWorkerCaches(any(), anyLong());
+        verify(mDelegateMock, times(1)).disableSyncAndWipeData(any(), anyLong(), eq(true), any());
     }
 
     @Test
@@ -107,8 +96,7 @@
         // Stub out various native calls. Some of these are verified as never called
         // and those stubs simply allow that verification to catch any issues.
         doNothing().when(mNativeMock).signOut(any(), anyLong(), anyInt());
-        doNothing().when(mNativeMock).wipeProfileData(any(), anyLong());
-        doNothing().when(mNativeMock).wipeGoogleServiceWorkerCaches(any(), anyLong());
+        doNothing().when(mDelegateMock).disableSyncAndWipeData(any(), anyLong(), eq(false), any());
         // See verification of nativeWipeGoogleServiceWorkerCaches below.
         doReturn(null).when(mNativeMock).getManagementDomain(any(), anyLong());
 
@@ -118,15 +106,12 @@
         // nativeSignOut should be called *before* clearing any account data.
         // http://crbug.com/589028
         verify(mNativeMock, times(1)).signOut(any(), anyLong(), eq(SignoutReason.SIGNOUT_TEST));
-        verify(mNativeMock, never()).wipeGoogleServiceWorkerCaches(any(), anyLong());
-        verify(mNativeMock, never()).wipeProfileData(any(), anyLong());
+        verify(mDelegateMock, never()).disableSyncAndWipeData(any(), anyLong(), eq(false), any());
 
         // Simulate native callback to trigger clearing of account data.
         mSigninManager.onNativeSignOut();
 
-        // Sign-out should only clear the service worker cache when the domain is null.
-        verify(mNativeMock, never()).wipeProfileData(any(), anyLong());
-        verify(mNativeMock, times(1)).wipeGoogleServiceWorkerCaches(any(), anyLong());
+        verify(mDelegateMock, times(1)).disableSyncAndWipeData(any(), anyLong(), eq(false), any());
     }
 
     @Test
@@ -134,8 +119,7 @@
         // Stub out various native calls. Some of these are verified as never called
         // and those stubs simply allow that verification to catch any issues.
         doNothing().when(mNativeMock).signOut(any(), anyLong(), anyInt());
-        doNothing().when(mNativeMock).wipeProfileData(any(), anyLong());
-        doNothing().when(mNativeMock).wipeGoogleServiceWorkerCaches(any(), anyLong());
+        doNothing().when(mDelegateMock).disableSyncAndWipeData(any(), anyLong(), eq(true), any());
         // See verification of nativeWipeProfileData below.
         doReturn("TestDomain").when(mNativeMock).getManagementDomain(any(), anyLong());
 
@@ -147,9 +131,7 @@
         // from the native side.
         verify(mNativeMock, never()).signOut(any(), anyLong(), anyInt());
 
-        // Sign-out should wipe profile data when user has managed domain.
-        verify(mNativeMock, times(1)).wipeProfileData(any(), anyLong());
-        verify(mNativeMock, never()).wipeGoogleServiceWorkerCaches(any(), anyLong());
+        verify(mDelegateMock, times(1)).disableSyncAndWipeData(any(), anyLong(), eq(true), any());
     }
 
     @Test
@@ -157,8 +139,7 @@
         // Stub out various native calls. Some of these are verified as never called
         // and those stubs simply allow that verification to catch any issues.
         doNothing().when(mNativeMock).signOut(any(), anyLong(), anyInt());
-        doNothing().when(mNativeMock).wipeProfileData(any(), anyLong());
-        doNothing().when(mNativeMock).wipeGoogleServiceWorkerCaches(any(), anyLong());
+        doNothing().when(mDelegateMock).disableSyncAndWipeData(any(), anyLong(), eq(false), any());
         // See verification of nativeWipeGoogleServiceWorkerCaches below.
         doReturn(null).when(mNativeMock).getManagementDomain(any(), anyLong());
 
@@ -170,9 +151,7 @@
         // from the native side.
         verify(mNativeMock, never()).signOut(any(), anyLong(), anyInt());
 
-        // Sign-out should only clear the service worker cache when the domain is null.
-        verify(mNativeMock, never()).wipeProfileData(any(), anyLong());
-        verify(mNativeMock, times(1)).wipeGoogleServiceWorkerCaches(any(), anyLong());
+        verify(mDelegateMock, times(1)).disableSyncAndWipeData(any(), anyLong(), eq(false), any());
     }
 
     @Test
@@ -193,7 +172,7 @@
                 .when(mNativeMock)
                 .signOut(any(), anyLong(), anyInt());
         doReturn(null).when(mNativeMock).getManagementDomain(any(), anyLong());
-        doNothing().when(mNativeMock).wipeGoogleServiceWorkerCaches(any(), anyLong());
+        doNothing().when(mNativeMock).wipeGoogleServiceWorkerCaches(any(), anyLong(), any());
 
         mSigninManager.signOut(SignoutReason.SIGNOUT_TEST);
         assertTrue(mSigninManager.isOperationInProgress());
@@ -212,7 +191,7 @@
         doReturn(true).when(mAccountTrackerService).checkAndSeedSystemAccounts();
         // Request that policy is loaded. It will pause sign-in until onPolicyCheckedBeforeSignIn is
         // invoked.
-        doNothing().when(mNativeMock).registerAndFetchPolicyBeforeSignIn(any(), anyLong(), any());
+        doNothing().when(mDelegateMock).fetchAndApplyCloudPolicy(any(), anyLong(), any());
 
         doReturn(true).when(mSigninManager).isSigninSupported();
         doNothing().when(mNativeMock).onSignInCompleted(any(), anyLong(), any());
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 92d7f2f..4184a57 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-77.0.3823.0_rc-r1-merged.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-77.0.3824.0_rc-r1-merged.afdo.bz2
\ No newline at end of file
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/DinoActivity.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/DinoActivity.java
index f04c096..dc746b4 100644
--- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/DinoActivity.java
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/DinoActivity.java
@@ -91,6 +91,12 @@
     }
 
     @Override
+    protected TabDelegateFactory createTabDelegateFactory() {
+        return new NoBrowserControlsTabDelegateFactory(
+                getFullscreenManager().getBrowserVisibilityDelegate());
+    }
+
+    @Override
     protected TabState restoreTabState(Bundle savedInstanceState, int tabId) {
         return null;
     }
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java
index a7723e9a..2125997d 100644
--- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java
@@ -210,6 +210,12 @@
     }
 
     @Override
+    protected TabDelegateFactory createTabDelegateFactory() {
+        return new NoBrowserControlsTabDelegateFactory(
+                getFullscreenManager().getBrowserVisibilityDelegate());
+    }
+
+    @Override
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
         saveTabState(outState);
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchTabDelegateFactory.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchTabDelegateFactory.java
new file mode 100644
index 0000000..eeb020f2
--- /dev/null
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchTabDelegateFactory.java
@@ -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.
+
+package org.chromium.chrome.browser.touchless;
+
+import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
+import org.chromium.chrome.browser.tab.TabDelegateFactory;
+
+/**
+ * TabDelegateFactory for all touchless activities.
+ */
+public class NoTouchTabDelegateFactory extends TabDelegateFactory {
+    private final BrowserControlsVisibilityDelegate mDelegate;
+
+    public NoTouchTabDelegateFactory(BrowserControlsVisibilityDelegate delegate) {
+        mDelegate = delegate;
+    }
+
+    @Override
+    public BrowserControlsVisibilityDelegate createBrowserControlsVisibilityDelegate(Tab tab) {
+        return mDelegate;
+    }
+}
diff --git a/chrome/android/touchless/touchless_java_sources.gni b/chrome/android/touchless/touchless_java_sources.gni
index d062140..ef1d2e35 100644
--- a/chrome/android/touchless/touchless_java_sources.gni
+++ b/chrome/android/touchless/touchless_java_sources.gni
@@ -15,6 +15,7 @@
   "touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabViewBinder.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabView.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/QuantizedSizeIconView.java",
+  "touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchTabDelegateFactory.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/ScrollPositionInfo.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionModel.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsAdapter.java",
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index e1a1c6e..d888fdc 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3066,7 +3066,7 @@
        Sharing <ph name="TAB_NAME">$1<ex>youtube.com</ex></ph> to <ph name="APP_NAME">$2<ex>meet.google.com</ex></ph>
       </message>
       <message name="IDS_TAB_SHARING_INFOBAR_SHARE_BUTTON" desc="Text displayed on the button to share current tab.">
-       Share this tab
+       Share this tab instead
       </message>
       <message name="IDS_TAB_SHARING_INFOBAR_STOP_BUTTON" desc="Text displayed on the button to stop sharing a tab.">
        Stop
@@ -6941,45 +6941,22 @@
       </if>
 
       <!--  Sync Confirmation section of the tab modal signin flow -->
-      <message name="IDS_SYNC_CONFIRMATION_TITLE" desc="Title of the sync confirmation dialog in the tab modal signin flow">
-        You've signed in and turned on Sync
-      </message>
-      <message name="IDS_SYNC_CONFIRMATION_DICE_TITLE" desc="Title of the sync confirmation dialog in the tab modal signin flow when Dice is enabled">
+      <message name="IDS_SYNC_CONFIRMATION_TITLE" desc="Title of the sync confirmation dialog in the tab modal signin flow when Dice is enabled">
         Turn on sync?
       </message>
-      <message name="IDS_SYNC_CONFIRMATION_UNITY_SYNC_INFO_TITLE" desc="Title in the information about sync on the sync confirmation dialog when Unity is enabled">
+      <message name="IDS_SYNC_CONFIRMATION_SYNC_INFO_TITLE" desc="Title in the information about sync on the sync confirmation dialog when Unity is enabled">
         Sync your bookmarks, passwords, history, and more on all your devices
       </message>
-      <message name="IDS_SYNC_CONFIRMATION_UNITY_SYNC_INFO_DESC" desc="Description in the information about sync on the sync confirmation dialog when Unity is enabled">
+      <message name="IDS_SYNC_CONFIRMATION_SYNC_INFO_DESC" desc="Description in the information about sync on the sync confirmation dialog when Unity is enabled">
         Google may use your history to personalize Search, ads, and other Google services
       </message>
-      <message name="IDS_SYNC_CONFIRMATION_UNITY_SETTINGS_INFO" desc="Information about customizing Sync settings in the sync confirmation dialog when Unity is enabled">
+      <message name="IDS_SYNC_CONFIRMATION_SETTINGS_INFO" desc="Information about customizing Sync settings in the sync confirmation dialog when Unity is enabled">
         You can always choose what to sync in settings.
       </message>
-
-      <!-- "Chrome sync" is the Google Cloud Based service used for sync. Thus this string resource is set to "Chrome sync" even for Chromium builds. -->
-      <message name="IDS_SYNC_CONFIRMATION_CHROME_SYNC_TITLE" desc="Title of the chrome sync section of the sync confirmation dialog in the tab modal signin flow" formatter_data="android_java">
-        Chrome Sync
-      </message>
-      <message name="IDS_SYNC_CONFIRMATION_CHROME_SYNC_MESSAGE" desc="Body of the chrome sync section of the sync confirmation dialog in the tab modal signin flow" formatter_data="android_java">
-        Your bookmarks, history, passwords, and other settings will be synced to your Google Account so you can use them on all your devices
-      </message>
-      <message name="IDS_SYNC_CONFIRMATION_PERSONALIZE_SERVICES_TITLE" desc="Title of the personalize services section of the sync confirmation dialog in the tab modal signin flow" formatter_data="android_java">
-        Personalize Google services
-      </message>
-      <message name="IDS_SYNC_CONFIRMATION_PERSONALIZE_SERVICES_BODY" desc="Body of the personalize services section of the sync confirmation dialog in the tab modal signin flow" formatter_data="android_java">
-        Google may use your browsing history to personalize Search, ads, and other Google services
-      </message>
-      <message name="IDS_SYNC_CONFIRMATION_PERSONALIZE_SERVICES_BODY_CHILD_ACCOUNT" desc="Body of the personalize services section of the sync confirmation dialog in the tab modal signin flow for child accounts" formatter_data="android_java">
-        Google may use your browsing history to personalize Search and other Google services
-      </message>
-      <message name="IDS_SYNC_CONFIRMATION_SYNC_SETTINGS_LINK_BODY" desc="Label of the section containing the link to go to the sync setting page.">
-        Want to manage sync and personalization before they’re turned on? Visit <ph name="BEGIN_LINK">&lt;a id="settingsLink" href="chrome://settings"&gt;</ph>Settings<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>.
-      </message>
-      <message name="IDS_SYNC_CONFIRMATION_DICE_CONFIRM_BUTTON_LABEL" desc="Label of the confirmation button in the sync confirmation dialog of the tab modal signin flow">
+      <message name="IDS_SYNC_CONFIRMATION_CONFIRM_BUTTON_LABEL" desc="Label of the confirmation button in the sync confirmation dialog of the tab modal signin flow">
         Yes, I'm in
       </message>
-      <message name="IDS_SYNC_CONFIRMATION_DICE_SETTINGS_BUTTON_LABEL" desc="Label of the button in the sync confirmation dialog of the tab modal signin flow to open settings">
+      <message name="IDS_SYNC_CONFIRMATION_SETTINGS_BUTTON_LABEL" desc="Label of the button in the sync confirmation dialog of the tab modal signin flow to open settings">
         Settings
       </message>
 
diff --git a/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_UNITY_SETTINGS_INFO.png.sha1 b/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_CONFIRM_BUTTON_LABEL.png.sha1
similarity index 100%
copy from chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_UNITY_SETTINGS_INFO.png.sha1
copy to chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_CONFIRM_BUTTON_LABEL.png.sha1
diff --git a/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_UNITY_SETTINGS_INFO.png.sha1 b/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_SETTINGS_BUTTON_LABEL.png.sha1
similarity index 100%
copy from chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_UNITY_SETTINGS_INFO.png.sha1
copy to chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_SETTINGS_BUTTON_LABEL.png.sha1
diff --git a/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_UNITY_SETTINGS_INFO.png.sha1 b/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_SETTINGS_INFO.png.sha1
similarity index 100%
rename from chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_UNITY_SETTINGS_INFO.png.sha1
rename to chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_SETTINGS_INFO.png.sha1
diff --git a/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_UNITY_SETTINGS_INFO.png.sha1 b/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_SYNC_INFO_DESC.png.sha1
similarity index 100%
copy from chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_UNITY_SETTINGS_INFO.png.sha1
copy to chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_SYNC_INFO_DESC.png.sha1
diff --git a/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_UNITY_SETTINGS_INFO.png.sha1 b/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_SYNC_INFO_TITLE.png.sha1
similarity index 100%
copy from chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_UNITY_SETTINGS_INFO.png.sha1
copy to chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_SYNC_INFO_TITLE.png.sha1
diff --git a/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_UNITY_SETTINGS_INFO.png.sha1 b/chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_TITLE.png.sha1
similarity index 100%
copy from chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_UNITY_SETTINGS_INFO.png.sha1
copy to chrome/app/generated_resources_grd/IDS_SYNC_CONFIRMATION_TITLE.png.sha1
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 47cdd39..d20b11c 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -1653,12 +1653,18 @@
     <message name="IDS_SETTINGS_KERBEROS_ACCOUNTS_ADD_ACCOUNT_LABEL" desc="Label of the Add account button on Kerberos Accounts Settings page.">
       Add account
     </message>
-    <message name="IDS_SETTINGS_KERBEROS_ACCOUNTS_SET_AS_ACTIVE_ACCOUNT_LABEL" desc="Label of the Set as active account button on Kerberos Accounts Settings page.">
+    <message name="IDS_SETTINGS_KERBEROS_ACCOUNTS_REFRESH_NOW_LABEL" desc="Label of the 'Refresh now' button on Kerberos Accounts Settings page.">
+      Refresh now
+    </message>
+    <message name="IDS_SETTINGS_KERBEROS_ACCOUNTS_SET_AS_ACTIVE_ACCOUNT_LABEL" desc="Label of the 'Set as active account' button on Kerberos Accounts Settings page.">
       Set as active account
     </message>
-    <message name="IDS_SETTINGS_KERBEROS_ACCOUNTS_REMOVE_ACCOUNT_LABEL" desc="Label of the Remove account button on Kerberos Accounts Settings page.">
+    <message name="IDS_SETTINGS_KERBEROS_ACCOUNTS_REMOVE_ACCOUNT_LABEL" desc="Label of the 'Remove account' button on Kerberos Accounts Settings page.">
       Remove account from this device
     </message>
+    <message name="IDS_SETTINGS_KERBEROS_ACCOUNTS_ADVANCED_CONFIG_LABEL" desc="Label of the button on Kerberos Accounts Settings page to get to the Advanced configuration dialog.">
+      Advanced configuration
+    </message>
     <message name="IDS_SETTINGS_KERBEROS_ACCOUNTS_SIGNED_IN" desc="Text displayed if a Kerberos account is in signed-in state on Kerberos Accounts Settings page.">
       Signed in
     </message>
@@ -1674,12 +1680,21 @@
     <message name="IDS_SETTINGS_ADD_KERBEROS_ACCOUNT_REMEMBER_PASSWORD" desc="In Add Kerberos Accounts dialog, label of the checkbox to remember the password.">
       Remember password
     </message>
+    <message name="IDS_SETTINGS_KERBEROS_ADVANCED_CONFIG_TITLE" desc="In Kerberos Advanced Configuration dialog, the title of the dialog.">
+      Advanced Kerberos configuration
+    </message>
+    <message name="IDS_SETTINGS_KERBEROS_ADVANCED_CONFIG_DESC" desc="In Kerberos Advanced Configuration dialog, the description of the dialog (below the title).">
+      Edit the Kerberos configuration file here.
+    </message>
     <message name="IDS_SETTINGS_KERBEROS_USERNAME" desc="Title for the input that lets users specify their username for a Kerberos account.">
       Username
     </message>
     <message name="IDS_SETTINGS_KERBEROS_PASSWORD" desc="Title for the input that lets users specify their password for a Kerberos account.">
       Password
     </message>
+    <message name="IDS_SETTINGS_KERBEROS_CONFIG" desc="In Kerberos Advanced Configuration dialog, label of the Kerberos configuration text area.">
+      Configuration
+    </message>
     <message name="IDS_SETTINGS_KERBEROS_ERROR_NETWORK_PROBLEM" desc="Error message displayed in the Add Kerberos Account dialog when the user has no network connection or enters a bad realm.">
       Network problem or bad realm
     </message>
@@ -1689,6 +1704,9 @@
     <message name="IDS_SETTINGS_KERBEROS_ERROR_USERNAME_UNKNOWN" desc="Error message displayed in the Add Kerberos Account dialog when the user enters a username that is not known to the Kerberos realm.">
       Username not known to server
     </message>
+    <message name="IDS_SETTINGS_KERBEROS_ERROR_DUPLICATE_PRINCIPAL_NAME" desc="Error message displayed in the Add Kerberos Account dialog when the user enters a username for which there is already an account.">
+      An account with this username already exists
+    </message>
     <message name="IDS_SETTINGS_KERBEROS_ERROR_CONTACTING_SERVER" desc="Error message displayed in the Add Kerberos Account dialog when the OS is not able to contact the server for the given realm.">
       Contacting server for realm failed
     </message>
@@ -1869,9 +1887,6 @@
     <message name="IDS_SETTINGS_INTERNET_CONFIG_SHARE" desc="Settings > Internet > Network config: Label for setting allowing other device users to use the network configuration.">
       Allow other users of this device to use this network
     </message>
-    <message name="IDS_SETTINGS_HIDDEN_NETWORK_WARNING" desc="Settings > Internet > Network config: Text shown when auto connect to the WiFi network is enabled, warning about the dangers of auto-connecting to hidden networks.">
-      Automatically connecting to a hidden network allows others to see your device and some network settings, and is not recommended.
-    </message>
     <message name="IDS_SETTINGS_INTERNET_CONFIG_SAVE_CREDENTIALS" desc="Settings > Internet > Network config: Label for the setting to save identity and password.">
       Save identity and password
     </message>
@@ -3729,6 +3744,9 @@
     <message name="IDS_SETTINGS_ACCOUNT_MANAGER_MANAGEMENT_STATUS_UNMANAGED_ACCOUNT" desc="Management status label for unmanaged accounts.">
       Primary account
     </message>
+    <message name="IDS_SETTINGS_ACCOUNT_MANAGER_ACCOUNT_REMOVED_MESSAGE" desc="Notification message after account removal.">
+      <ph name="EMAIL">$1<ex>abcd@google.com</ex></ph> was removed from this device
+    </message>
     <message name="IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_TITLE" desc="Title of the add fingerprint dialog popup.">
       Set up your fingerprint
     </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_HIDDEN_NETWORK_WARNING.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_HIDDEN_NETWORK_WARNING.png.sha1
deleted file mode 100644
index fd39eb1..0000000
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_HIDDEN_NETWORK_WARNING.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-7b67f22ff91633353d0c6e3e61cd2bdfd75aab9a
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index acfd23a8..815a6003 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2737,10 +2737,8 @@
       "profiles/profile_android.h",
       "search/contextual_search_policy_handler_android.cc",
       "search/contextual_search_policy_handler_android.h",
-      "search_engines/template_url_android.cc",
-      "search_engines/template_url_android.h",
-      "search_engines/template_url_service_android.cc",
-      "search_engines/template_url_service_android.h",
+      "search_engines/template_url_service_factory_android.cc",
+      "search_engines/template_url_service_factory_android.h",
       "signin/identity_services_provider_android.cc",
       "ssl/security_state_model_android.cc",
       "sync/glue/synced_tab_delegate_android.cc",
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.h b/chrome/browser/android/ntp/ntp_snippets_bridge.h
index 9460960..2a80e702 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.h
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.h
@@ -14,6 +14,7 @@
 #include "components/ntp_snippets/category_status.h"
 #include "components/ntp_snippets/content_suggestions_service.h"
 #include "components/ntp_snippets/status.h"
+#include "components/prefs/pref_change_registrar.h"
 
 namespace gfx {
 class Image;
diff --git a/chrome/browser/android/signin/signin_manager_android.cc b/chrome/browser/android/signin/signin_manager_android.cc
index 6ff3228f..f3527ebd 100644
--- a/chrome/browser/android/signin/signin_manager_android.cc
+++ b/chrome/browser/android/signin/signin_manager_android.cc
@@ -195,19 +195,24 @@
   return domain;
 }
 
-void SigninManagerAndroid::WipeProfileData(JNIEnv* env,
-                                           const JavaParamRef<jobject>& obj) {
-  WipeData(profile_, true /* all data */,
-           base::Bind(&SigninManagerAndroid::OnBrowsingDataRemoverDone,
-                      weak_factory_.GetWeakPtr()));
+void SigninManagerAndroid::WipeProfileData(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& j_callback) {
+  WipeData(
+      profile_, true /* all data */,
+      base::BindOnce(base::android::RunRunnableAndroid,
+                     base::android::ScopedJavaGlobalRef<jobject>(j_callback)));
 }
 
 void SigninManagerAndroid::WipeGoogleServiceWorkerCaches(
     JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  WipeData(profile_, false /* only Google service worker caches */,
-           base::Bind(&SigninManagerAndroid::OnBrowsingDataRemoverDone,
-                      weak_factory_.GetWeakPtr()));
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& j_callback) {
+  WipeData(
+      profile_, false /* only Google service worker caches */,
+      base::BindOnce(base::android::RunRunnableAndroid,
+                     base::android::ScopedJavaGlobalRef<jobject>(j_callback)));
 }
 
 void SigninManagerAndroid::RegisterPolicyWithAccount(
@@ -235,7 +240,7 @@
           std::move(callback))));
 }
 
-void SigninManagerAndroid::RegisterAndFetchPolicyBeforeSignIn(
+void SigninManagerAndroid::FetchAndApplyCloudPolicy(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     const JavaParamRef<jstring>& j_username) {
@@ -288,11 +293,6 @@
       base::android::AttachCurrentThread(), java_signin_manager_);
 }
 
-void SigninManagerAndroid::OnBrowsingDataRemoverDone() {
-  Java_SigninManager_onProfileDataWiped(base::android::AttachCurrentThread(),
-                                        java_signin_manager_);
-}
-
 void SigninManagerAndroid::ClearLastSignedInUser(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj) {
diff --git a/chrome/browser/android/signin/signin_manager_android.h b/chrome/browser/android/signin/signin_manager_android.h
index 6bce23d..55d90fd2 100644
--- a/chrome/browser/android/signin/signin_manager_android.h
+++ b/chrome/browser/android/signin/signin_manager_android.h
@@ -31,7 +31,7 @@
 
   // Registers a CloudPolicyClient for fetching policy for a user and fetches
   // the policy if necessary.
-  void RegisterAndFetchPolicyBeforeSignIn(
+  void FetchAndApplyCloudPolicy(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
       const base::android::JavaParamRef<jstring>& username);
@@ -55,12 +55,14 @@
 
   // Delete all data for this profile.
   void WipeProfileData(JNIEnv* env,
-                       const base::android::JavaParamRef<jobject>& obj);
+                       const base::android::JavaParamRef<jobject>& obj,
+                       const base::android::JavaParamRef<jobject>& j_callback);
 
   // Delete service worker caches for google.<eTLD>.
   void WipeGoogleServiceWorkerCaches(
       JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj);
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobject>& j_callback);
 
   void LogInSignedInUser(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>& obj);
diff --git a/chrome/browser/android/startup_bridge.cc b/chrome/browser/android/startup_bridge.cc
index d92c449..718db043 100644
--- a/chrome/browser/android/startup_bridge.cc
+++ b/chrome/browser/android/startup_bridge.cc
@@ -22,4 +22,11 @@
   Java_NativeStartupBridge_loadFullBrowser(env);
 }
 
+void HandlePostNativeStartupSynchronously() {
+  // The C++ initialization of the browser has already been done.
+  DCHECK(g_browser_process);
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_NativeStartupBridge_handlePostNativeStartupSynchronously(env);
+}
+
 }  // namespace android_startup
diff --git a/chrome/browser/android/startup_bridge.h b/chrome/browser/android/startup_bridge.h
index 913cef9..0c1b40b 100644
--- a/chrome/browser/android/startup_bridge.h
+++ b/chrome/browser/android/startup_bridge.h
@@ -7,6 +7,11 @@
 
 namespace android_startup {
 extern void LoadFullBrowser();
+
+// Called to start up java bits of chrome synchronously after the C++ bits have
+// been initialized. Used for browser tests which must run the browser
+// synchronously before running the test.
+extern void HandlePostNativeStartupSynchronously();
 }
 
 #endif  // CHROME_BROWSER_ANDROID_STARTUP_BRIDGE_H_
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc
index bc22ecd..f9bc6833 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.cc
+++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -512,7 +512,7 @@
   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
   if (obj.is_null())
     return false;
-  return Java_TabWebContentsDelegateAndroid_isNightModeEnabled(env, obj);
+  return Java_TabWebContentsDelegateAndroid_isPictureInPictureEnabled(env, obj);
 }
 
 bool TabWebContentsDelegateAndroid::IsNightModeEnabled() const {
@@ -520,7 +520,7 @@
   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
   if (obj.is_null())
     return false;
-  return Java_TabWebContentsDelegateAndroid_isPictureInPictureEnabled(env, obj);
+  return Java_TabWebContentsDelegateAndroid_isNightModeEnabled(env, obj);
 }
 
 const GURL TabWebContentsDelegateAndroid::GetManifestScope() const {
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index fae9ad4..cf6c32db 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -768,10 +768,12 @@
 
   // Record the path to the (browser) app bundle; this is used by the app mode
   // shim.
-  base::PostTaskWithTraits(FROM_HERE,
-                           {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
-                            base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-                           base::BindOnce(&RecordLastRunAppBundlePath));
+  if (base::mac::AmIBundled()) {
+    base::PostTaskWithTraits(FROM_HERE,
+                             {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+                              base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+                             base::BindOnce(&RecordLastRunAppBundlePath));
+  }
 
   // Makes "Services" menu items available.
   [self registerServicesMenuTypesTo:[notify object]];
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index ad62956..bdae3bd 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2777,7 +2777,11 @@
   // If we pass 0 for size, disk_cache will pick a default size using the
   // heuristics based on available disk size. These are implemented in
   // disk_cache::PreferredCacheSize in net/disk_cache/cache_util.cc.
-  return content::GeneratedCodeCacheSettings(true, 0, cache_path);
+  int64_t size_in_bytes = 0;
+  PrefService* prefs = Profile::FromBrowserContext(context)->GetPrefs();
+  DCHECK(prefs);
+  size_in_bytes = prefs->GetInteger(prefs::kDiskCacheSize);
+  return content::GeneratedCodeCacheSettings(true, size_in_bytes, cache_path);
 }
 
 void ChromeContentBrowserClient::AllowCertificateError(
diff --git a/chrome/browser/chromeos/chrome_content_browser_client_chromeos_part_browsertest.cc b/chrome/browser/chromeos/chrome_content_browser_client_chromeos_part_browsertest.cc
index 7509cd14..6db4fc8 100644
--- a/chrome/browser/chromeos/chrome_content_browser_client_chromeos_part_browsertest.cc
+++ b/chrome/browser/chromeos/chrome_content_browser_client_chromeos_part_browsertest.cc
@@ -6,6 +6,8 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
+#include "chrome/browser/web_applications/system_web_app_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/constants/chromeos_features.h"
@@ -17,6 +19,11 @@
 
 IN_PROC_BROWSER_TEST_F(ChromeContentBrowserClientChromeOsPartTest,
                        SettingsWindowFontSize) {
+  // Install the Settings App.
+  web_app::WebAppProvider::Get(browser()->profile())
+      ->system_web_app_manager()
+      .InstallSystemAppsForTesting();
+
   const content::WebPreferences kDefaultPrefs;
   const int kDefaultFontSize = kDefaultPrefs.default_font_size;
   const int kDefaultFixedFontSize = kDefaultPrefs.default_fixed_font_size;
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index 4d915739..0bcaabd7 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -203,6 +203,8 @@
       FinishRestart(result);
       return;
     }
+    // Set the pref here, after we first successfully install something
+    profile_->GetPrefs()->SetBoolean(crostini::prefs::kCrostiniEnabled, true);
     crostini_manager_->StartConcierge(
         base::BindOnce(&CrostiniRestarter::ConciergeStarted, this));
   }
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
index be0311a..36ce9d42 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/chromeos/crostini/crostini_pref_names.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/common/chrome_features.h"
@@ -748,6 +749,8 @@
                      base::Unretained(this), run_loop()->QuitClosure()),
       this);
   run_loop()->Run();
+  EXPECT_FALSE(
+      profile_->GetPrefs()->GetBoolean(crostini::prefs::kCrostiniEnabled));
   EXPECT_FALSE(fake_concierge_client_->create_disk_image_called());
   EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called());
   EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index b63a49f7..bc5a335 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -298,7 +298,9 @@
         TestCase("fileSearchCaseInsensitive"),
         TestCase("fileSearchNotFound"),
         TestCase("fileDisplayDownloadsWithBlockedFileTaskRunner"),
-        TestCase("fileDisplayCheckSelectWithFakeItemSelected")));
+        TestCase("fileDisplayCheckSelectWithFakeItemSelected"),
+        TestCase("fileDisplayCheckReadOnlyIconOnFakeDirectory"),
+        TestCase("fileDisplayCheckNoReadOnlyIconOnDownloads")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
     OpenVideoFiles, /* open_video_files.js */
@@ -333,9 +335,13 @@
                       TestCase("imageOpenDownloads"),
                       TestCase("imageOpenDrive").DisableDriveFs(),
                       TestCase("imageOpenDrive").EnableDriveFs(),
-                      TestCase("imageOpenGalleryOpenDownloads"),
+                      TestCase("imageOpenGalleryOpenDownloads")
+#if 0  // Flaky. crbug.com/973795
+                      ,
                       TestCase("imageOpenGalleryOpenDrive").DisableDriveFs(),
-                      TestCase("imageOpenGalleryOpenDrive").EnableDriveFs()));
+                      TestCase("imageOpenGalleryOpenDrive").EnableDriveFs()
+#endif
+                          ));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
     OpenSniffedFiles, /* open_sniffed_files.js */
@@ -496,7 +502,8 @@
         TestCase("checkDeleteDisabledInDocProvider").EnableDocumentsProvider(),
         TestCase("checkDeleteEnabledInDocProvider").EnableDocumentsProvider(),
         TestCase("checkRenameDisabledInDocProvider").EnableDocumentsProvider(),
-        TestCase("checkRenameEnabledInDocProvider").EnableDocumentsProvider()));
+        TestCase("checkRenameEnabledInDocProvider").EnableDocumentsProvider(),
+        TestCase("checkContextMenuFocus").EnableMyFilesVolume()));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
     Delete, /* delete.js */
@@ -607,7 +614,8 @@
         TestCase("dirContextMenuSharedWithMe"),
         TestCase("dirContextMenuOffline"),
         TestCase("dirContextMenuComputers"),
-        TestCase("dirContextMenuShortcut")));
+        TestCase("dirContextMenuShortcut"),
+        TestCase("dirContextMenuFocus")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
     DriveSpecific, /* drive_specific.js */
diff --git a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
index 5726de1..f01700c 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
@@ -698,6 +698,7 @@
              IDS_FILE_BROWSER_QUICK_VIEW_OPEN_IN_NEW_BUTTON_LABEL);
   SET_STRING("QUICK_VIEW_TOGGLE_METADATA_BOX_BUTTON_LABEL",
              IDS_FILE_BROWSER_QUICK_VIEW_TOGGLE_METADATA_BOX_BUTTON_LABEL);
+  SET_STRING("READ_ONLY_LABEL", IDS_FILE_BROWSER_READ_ONLY_LABEL);
   SET_STRING("REFRESH_BUTTON_LABEL", IDS_FILE_BROWSER_REFRESH_BUTTON_LABEL);
   SET_STRING("REMOVABLE_DEVICE_DETECTION_TITLE",
              IDS_REMOVABLE_DEVICE_DETECTION_TITLE);
diff --git a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
index 0e97bb12..11d94ad9 100644
--- a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
+++ b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
@@ -38,13 +38,10 @@
 constexpr char kLoginEmail[] = "LOGIN_EMAIL";
 
 // Default encryption with strong encryption.
-constexpr char kDefaultKerberosConfigFmt[] = R"(
-[libdefaults]
+constexpr char kDefaultKerberosConfig[] = R"([libdefaults]
   default_tgs_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
   default_tkt_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
-  permitted_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
-  default_realm = %s
-)";
+  permitted_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96)";
 
 // If |principal_name| is "UsEr@realm.com", sets |principal_name| to
 // "user@REALM.COM". Returns false if the given name has no @ or one of the
@@ -72,23 +69,6 @@
   return false;
 }
 
-// If |normalized_principal| is "user@REALM.COM", returns "REALM.COM".
-// DCHECKs valid format.
-std::string GetRealm(const std::string& normalized_principal) {
-  std::vector<std::string> parts = base::SplitString(
-      normalized_principal, "@", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-  DCHECK(parts.size() == 2);
-  DCHECK(!parts[1].empty());
-  return parts[1];
-}
-
-// Returns the default Kerberos configuration, with realm set based on
-// |normalized_principal|.
-std::string GetDefaultKerberosConfig(const std::string& normalized_principal) {
-  const std::string realm = GetRealm(normalized_principal);
-  return base::StringPrintf(kDefaultKerberosConfigFmt, realm.c_str());
-}
-
 // Logs an error if |error| is not |ERROR_NONE|.
 void LogError(const char* function_name, kerberos::ErrorType error) {
   LOG_IF(ERROR, error != kerberos::ERROR_NONE)
@@ -103,10 +83,9 @@
 }  // namespace
 
 // Encapsulates the steps to add a Kerberos account. Overview of the flow:
-// - Call the daemon's AddAccount. Handle errors duplicate errors transparently,
-//   it's OK if the account is already present.
-// - If |krb5_conf| is set (e.g. through policy), call daemon's SetConfig.
-//   Otherwise, if the account is new, set a default config.
+// - Call the daemon's AddAccount. Ignores duplicate account errors if
+//   |allow_existing| is true.
+// - Call daemon's SetConfig.
 // - If |password| is set, call daemon's AcquireKerberosTgt.
 // - Call manager's OnAddAccountRunnerDone.
 // If an error happens on any step, removes account if it was newly added and
@@ -118,14 +97,19 @@
   // |normalized_principal| is the normalized user principal name, e.g.
   // user@REALM.COM. |is_managed| is true for accounts set by admins via policy.
   // |password| is the password of the account. If |remember_password| is true,
-  // the password is remembered by the daemon. |callback| is called by
-  // OnAddAccountRunnerDone() at the end of the flow, see class description.
+  // the password is remembered by the daemon. |krb5_conf| is set as
+  // configuration. If |allow_existing| is false and an account for
+  // |principal_name| already exists, no action is performed and the method
+  // returns with ERROR_DUPLICATE_PRINCIPAL_NAME. If true, the existing account
+  // is updated. |callback| is called by OnAddAccountRunnerDone() at the end of
+  // the flow, see class description.
   KerberosAddAccountRunner(KerberosCredentialsManager* manager,
                            std::string normalized_principal,
                            bool is_managed,
                            const base::Optional<std::string>& password,
                            bool remember_password,
-                           const base::Optional<std::string>& krb5_conf,
+                           const std::string& krb5_conf,
+                           bool allow_existing,
                            KerberosCredentialsManager::ResultCallback callback)
       : manager_(manager),
         normalized_principal_(normalized_principal),
@@ -133,6 +117,7 @@
         password_(password),
         remember_password_(remember_password),
         krb5_conf_(krb5_conf),
+        allow_existing_(allow_existing),
         callback_(std::move(callback)) {
     AddAccount();
   }
@@ -147,15 +132,16 @@
                                 weak_factory_.GetWeakPtr()));
   }
 
-  // Forwards to MaybeSetConfig() if there was no error (other than a duplicate
-  // account, which is handled transparently). Calls Done() on error.
+  // Forwards to SetConfig() if there was no error (other than a managed account
+  // overwriting an existing one, which is handled transparently). Calls Done()
+  // on error.
   void OnAddAccount(const kerberos::AddAccountResponse& response) {
     is_new_account_ = response.error() == kerberos::ERROR_NONE;
     const bool is_existing_account =
         response.error() == kerberos::ERROR_DUPLICATE_PRINCIPAL_NAME;
 
-    if (is_new_account_ || is_existing_account) {
-      MaybeSetConfig();
+    if (is_new_account_ || (is_existing_account && allow_existing_)) {
+      SetConfig();
       return;
     }
 
@@ -163,25 +149,11 @@
     Done(response.error());
   }
 
-  // Figures out whether a configuration should be set and sets it:
-  //  - If |krb5_conf_| is set, use it.
-  //  - If the account is new, set a default configuration.
-  //  Otherwise, continues with MaybeAcquireKerberosTgt().
-  void MaybeSetConfig() {
+  // Set the Kerberos configuration.
+  void SetConfig() {
     kerberos::SetConfigRequest request;
-    if (krb5_conf_) {
-      // A configuration is set, so use that.
-      request.set_krb5conf(*krb5_conf_);
-    } else if (is_new_account_) {
-      // Set default configuration for a default account.
-      request.set_krb5conf(GetDefaultKerberosConfig(normalized_principal_));
-    } else {
-      // No configuration to set (don't overwrite an existing one!), so move on.
-      MaybeAcquireKerberosTgt();
-      return;
-    }
-
     request.set_principal_name(normalized_principal_);
+    request.set_krb5conf(krb5_conf_);
     KerberosClient::Get()->SetConfig(
         request, base::BindOnce(&KerberosAddAccountRunner::OnSetConfig,
                                 weak_factory_.GetWeakPtr()));
@@ -264,7 +236,8 @@
   bool is_managed_ = false;
   base::Optional<std::string> password_;
   bool remember_password_ = false;
-  const base::Optional<std::string> krb5_conf_;
+  std::string krb5_conf_;
+  bool allow_existing_ = false;
   KerberosCredentialsManager::ResultCallback callback_;
 
   // Whether the account was newly added.
@@ -358,6 +331,11 @@
   });
 }
 
+// static
+const char* KerberosCredentialsManager::GetDefaultKerberosConfig() {
+  return kDefaultKerberosConfig;
+}
+
 void KerberosCredentialsManager::AddObserver(Observer* observer) {
   observers_.AddObserver(observer);
 }
@@ -371,14 +349,15 @@
     bool is_managed,
     const base::Optional<std::string>& password,
     bool remember_password,
-    const base::Optional<std::string>& krb5_conf,
+    const std::string& krb5_conf,
+    bool allow_existing,
     ResultCallback callback) {
   if (!NormalizePrincipalOrPostCallback(&principal_name, &callback))
     return;
 
   add_account_runners_.push_back(std::make_unique<KerberosAddAccountRunner>(
       this, principal_name, is_managed, password, remember_password, krb5_conf,
-      std::move(callback)));
+      allow_existing, std::move(callback)));
   // The runner starts automatically and calls OnAddAccountRunnerDone when it's
   // done.
 }
@@ -521,6 +500,12 @@
     ResultCallback callback,
     const kerberos::SetConfigResponse& response) {
   LogError("SetConfig", response.error());
+
+  if (Succeeded(response.error())) {
+    // Yell out to the world that the config changed.
+    NotifyAccountsChanged();
+  }
+
   std::move(callback).Run(response.error());
 }
 
@@ -645,8 +630,8 @@
     bool remember_password =
         account.FindBoolKey(kRememberPassword).value_or(false);
 
-    // Get Kerberos configuration, default to GetDefaultKerberosConfig() to make
-    // sure it overwrites an existing unmanaged account.
+    // Get Kerberos configuration if given. Otherwise, use default to make sure
+    // it overwrites an existing unmanaged account.
     std::string krb5_conf;
     const base::Value* krb5_conf_value = account.FindPath(kKrb5Conf);
     if (krb5_conf_value) {
@@ -656,12 +641,14 @@
         krb5_conf += "\n";
       }
     } else {
-      krb5_conf = GetDefaultKerberosConfig(principal);
+      krb5_conf = kDefaultKerberosConfig;
     }
 
+    // By setting allow_existing == true, existing managed accounts are updated
+    // and existing unmanaged accounts are overwritten.
     add_account_runners_.push_back(std::make_unique<KerberosAddAccountRunner>(
         this, principal, true /* is_managed */, password, remember_password,
-        krb5_conf, EmptyResultCallback()));
+        krb5_conf, true /* allow_existing */, EmptyResultCallback()));
   }
 }
 
diff --git a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h
index cd7dd5e..6527199 100644
--- a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h
+++ b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h
@@ -62,25 +62,31 @@
   // Helper method for ignoring the results of method calls.
   static ResultCallback EmptyResultCallback();
 
+  // Returns the default Kerberos configuration (krb5.conf).
+  static const char* GetDefaultKerberosConfig();
+
   // Start observing this object. |observer| is not owned.
   void AddObserver(Observer* observer);
 
   // Stop observing this object. |observer| is not owned.
   void RemoveObserver(const Observer* observer);
 
-  // Adds an account for the given |principal_name|. If |is_managed| is true,
-  // the account is assumed to be managed by an admin and it overwrites any
-  // existing unmanaged account. If |password| is given, authenticates the
-  // account. If |remember_password| is true and a |password| is given, the
-  // Kerberos daemon remembers the password. |krb5_conf| is set as configuration
-  // if given. Sets a default configuration for new accounts if |krb5_conf| is
-  // not given. On success, sets |principal_name| as active principal and calls
-  // OnAccountsChanged() for observers.
+  // Adds an account for the given |principal_name| (user@example.com). If
+  // |is_managed| is true, the account is assumed to be managed by an admin and
+  // it overwrites any existing unmanaged account. If |password| is given,
+  // authenticates the account. If |remember_password| is true and a |password|
+  // is given, the Kerberos daemon remembers the password. |krb5_conf| is set as
+  // configuration. On success, sets |principal_name| as active principal and
+  // calls OnAccountsChanged() for observers. If |allow_existing| is false and
+  // an account for |principal_name| already exists, no action is performed and
+  // the method returns with ERROR_DUPLICATE_PRINCIPAL_NAME. If true, the
+  // existing account is updated.
   void AddAccountAndAuthenticate(std::string principal_name,
                                  bool is_managed,
                                  const base::Optional<std::string>& password,
                                  bool remember_password,
-                                 const base::Optional<std::string>& krb5_conf,
+                                 const std::string& krb5_conf,
+                                 bool allow_existing,
                                  ResultCallback callback);
 
   // Removes the Kerberos account for the account with given |principal_name|.
diff --git a/chrome/browser/chromeos/login/kiosk_browsertest.cc b/chrome/browser/chromeos/login/kiosk_browsertest.cc
index 834fe1a..dbd880ca 100644
--- a/chrome/browser/chromeos/login/kiosk_browsertest.cc
+++ b/chrome/browser/chromeos/login/kiosk_browsertest.cc
@@ -68,6 +68,7 @@
 #include "chromeos/dbus/cryptohome/cryptohome_client.h"
 #include "chromeos/disks/disk_mount_manager.h"
 #include "chromeos/settings/cros_settings_provider.h"
+#include "chromeos/tpm/stub_install_attributes.h"
 #include "components/crx_file/crx_verifier.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/scoped_user_manager.h"
@@ -113,6 +114,10 @@
 //       detail/ggaeimfdpnmlhdhpcikgoblffmkckdmn
 const char kTestKioskApp[] = "ggaeimfdpnmlhdhpcikgoblffmkckdmn";
 
+// This is the same as above, but packed in deprecated CRX2. It should work
+// before full deprecation of CRX2.
+const char kTestKioskCrx2App[] = "ggbflgnkafappblpkiflbgpmkfdpnhhe";
+
 // This app creates a window and declares usage of the identity API in its
 // manifest, so we can test device robot token minting via the identity API.
 // Webstore data json is in
@@ -467,10 +472,7 @@
 
 class KioskTest : public OobeBaseTest {
  public:
-  KioskTest()
-      : settings_helper_(false),
-        fake_cws_(new FakeCWS),
-        verifier_format_override_(crx_file::VerifierFormat::CRX3) {
+  KioskTest() : settings_helper_(false), fake_cws_(new FakeCWS) {
     set_exit_when_last_browser_closes(false);
 
     // This test does not operate any real App, so App data does not exist.
@@ -837,8 +839,6 @@
   std::string test_crx_file_;
   std::unique_ptr<FakeCWS> fake_cws_;
   std::unique_ptr<MockUserManager> mock_user_manager_;
-  extensions::SandboxedUnpacker::ScopedVerifierFormatOverrideForTest
-      verifier_format_override_;
 
   DISALLOW_COPY_AND_ASSIGN(KioskTest);
 };
@@ -1360,6 +1360,39 @@
   EXPECT_FALSE(login_display_host->GetAppLaunchController());
 }
 
+class KioskCrx2Test : public KioskTest {
+ public:
+  KioskCrx2Test()
+      : KioskTest(),
+        test_install_attributes_(
+            chromeos::StubInstallAttributes::CreateCloudManaged("example.com",
+                                                                "fake-id")) {}
+
+ private:
+  // Set up fake install attributes to make the device appeared as
+  // enterprise-managed. This is needed because CRX2 is only allowed for
+  // policy-based kiosk apps.
+  chromeos::ScopedStubInstallAttributes test_install_attributes_;
+
+  DISALLOW_COPY_AND_ASSIGN(KioskCrx2Test);
+};
+
+// Test that CRX2-packed apps still work for kiosk. This is a regression for
+// crbug.com/960428. TODO(crbug.com/740715): This test should fail in M78 after
+// full deprecation of CRX2.
+IN_PROC_BROWSER_TEST_F(KioskCrx2Test, InstallAndLaunchCrx2App) {
+  set_test_app_id(kTestKioskCrx2App);
+  set_test_crx_file(test_app_id() + ".crx");
+  set_use_consumer_kiosk_mode(false);
+  StartAppLaunchFromLoginScreen(
+      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
+  WaitForAppLaunchSuccess();
+  KioskAppManager::App app;
+  ASSERT_TRUE(KioskAppManager::Get()->GetApp(test_app_id(), &app));
+  EXPECT_FALSE(app.was_auto_launched_with_zero_delay);
+  EXPECT_EQ(extensions::Manifest::EXTERNAL_POLICY, GetInstalledAppLocation());
+}
+
 class KioskUpdateTest : public KioskTest {
  public:
   KioskUpdateTest() {}
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index d99a1174..0a52c5082 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -6729,14 +6729,7 @@
   DISALLOW_COPY_AND_ASSIGN(WebAppInstallForceListPolicyTest);
 };
 
-// TODO(crbug.com/878797): Flaky on windows
-#if defined(OS_WIN)
-#define MAYBE_StartUpInstallation DISABLED_StartUpInstallation
-#else
-#define MAYBE_StartUpInstallation StartUpInstallation
-#endif
-IN_PROC_BROWSER_TEST_F(WebAppInstallForceListPolicyTest,
-                       MAYBE_StartUpInstallation) {
+IN_PROC_BROWSER_TEST_F(WebAppInstallForceListPolicyTest, StartUpInstallation) {
   extensions::TestExtensionRegistryObserver observer(
       extensions::ExtensionRegistry::Get(browser()->profile()));
   const extensions::Extension* installed_extension =
diff --git a/chrome/browser/profiles/profile_key.cc b/chrome/browser/profiles/profile_key.cc
index 602030c..b796a44 100644
--- a/chrome/browser/profiles/profile_key.cc
+++ b/chrome/browser/profiles/profile_key.cc
@@ -13,6 +13,12 @@
 
 ProfileKey::~ProfileKey() = default;
 
+ProfileKey* ProfileKey::GetOriginalKey() {
+  if (original_key_)
+    return original_key_;
+  return this;
+}
+
 PrefService* ProfileKey::GetPrefs() {
   DCHECK(prefs_);
   return prefs_;
diff --git a/chrome/browser/profiles/profile_key.h b/chrome/browser/profiles/profile_key.h
index ed4ca905..a941019 100644
--- a/chrome/browser/profiles/profile_key.h
+++ b/chrome/browser/profiles/profile_key.h
@@ -20,7 +20,7 @@
   ~ProfileKey() override;
 
   // Profile-specific APIs needed in reduced mode:
-  ProfileKey* GetOriginalKey() { return original_key_; }
+  ProfileKey* GetOriginalKey();
   PrefService* GetPrefs();
   void SetPrefs(PrefService* prefs);
 
diff --git a/chrome/browser/resources/chromeos/camera/src/css/main.css b/chrome/browser/resources/chromeos/camera/src/css/main.css
index 65253635..da6704bf 100644
--- a/chrome/browser/resources/chromeos/camera/src/css/main.css
+++ b/chrome/browser/resources/chromeos/camera/src/css/main.css
@@ -517,7 +517,7 @@
   --bottom-line: 56px;
   --mode-item-height: 48px;
   --modes-bottom: calc((var(--bottom-line) + (var(--big-icon) / 2)) + 24px);
-  --modes-gradient-padding: 24px;
+  --modes-gradient-padding: 16px;
   --modes-height: 140px;
   --small-icon: 40px;
 }
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index dbbd9eb..01672f3b 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -1005,9 +1005,7 @@
   visibility: visible;
 }
 
-#backgrounds-menu .bg-sel-tile-bg,
-#backgrounds-image-menu .bg-sel-tile-bg,
-#colors-menu .bg-sel-tile-bg {
+#customization-menu .bg-sel-tile-bg {
   border-radius: 4px;
   height: 176px;
   margin-bottom: 45px;
@@ -1017,22 +1015,25 @@
   width: 176px;
 }
 
-#backgrounds-image-menu .bg-sel-tile-bg,
-#colors-menu .bg-sel-tile-bg {
+#backgrounds-image-menu .bg-sel-tile-bg {
   margin-bottom: 8px;
 }
 
-.selected #backgrounds-default-icon,
-#backgrounds-image-menu .bg-sel-tile-bg.selected .bg-sel-tile,
-#colors-menu .bg-sel-tile-bg.selected .bg-sel-tile {
+#colors-menu .bg-sel-tile-bg {
+  height: 120px;
+}
+
+#customization-menu .bg-sel-tile-bg.selected .bg-sel-tile {
   height: 144px;
   margin: 16px 16px 0 16px;
   width: 144px;
 }
 
-#backgrounds-menu .bg-sel-tile-bg.selected .bg-sel-tile:focus,
-#backgrounds-image-menu .bg-sel-tile-bg.selected .bg-sel-tile:focus,
-#colors-menu .bg-sel-tile-bg.selected .bg-sel-tile:focus {
+#colors-menu .bg-sel-tile-bg.selected .bg-sel-tile {
+  height: 88px;
+}
+
+#customization-menu .bg-sel-tile-bg.selected .bg-sel-tile:focus {
   outline: none;
 }
 
@@ -1040,15 +1041,12 @@
   outline: none;
 }
 
-#backgrounds-menu .bg-sel-tile,
-#backgrounds-image-menu .bg-sel-tile,
-#colors-menu .bg-sel-tile {
+#customization-menu .bg-sel-tile {
   background-position: center;
   border-radius: 4px;
 }
 
-#backgrounds-menu .bg-sel-tile-title,
-#colors-menu .bg-sel-tile-title {
+#customization-menu .bg-sel-tile-title {
   background-color: unset;
   color: rgb(var(--GG700-rgb));
   font-size: 13px;
@@ -1057,8 +1055,7 @@
   padding: 8px 0 24px 0;
 }
 
-html[darkmode=true] #backgrounds-menu .bg-sel-tile-title,
-html[darkmode=true] #colors-menu .bg-sel-tile-title {
+html[darkmode=true] #customization-menu .bg-sel-tile-title {
   color: rgb(var(--GG200-rgb));
 }
 
@@ -1070,9 +1067,7 @@
   width: 174px;
 }
 
-#backgrounds-default.selected,
-#backgrounds-image-menu .bg-sel-tile-bg.selected,
-#colors-menu .bg-sel-tile-bg.selected  {
+#customization-menu .bg-sel-tile-bg.selected  {
   background-color: rgba(var(--GB900-rgb), .08);
 }
 
diff --git a/chrome/browser/resources/settings/controls/settings_textarea.html b/chrome/browser/resources/settings/controls/settings_textarea.html
index 04e44c93d..f261cfa 100644
--- a/chrome/browser/resources/settings/controls/settings_textarea.html
+++ b/chrome/browser/resources/settings/controls/settings_textarea.html
@@ -21,10 +21,10 @@
     </style>
     <div id="label" hidden="[[!label]]">[[label]]</div>
     <div id="input-container">
-      <!-- The textarea will default to 3-row height, and if the content
-           exceeds the bounds, it will scroll by default. No space or comments
-           allowed before closing tag. -->
-      <textarea id="input" autofocus="[[autofocus]]" rows="3"
+      <!-- The textarea is limited to |rows| height. If the content exceeds the
+           bounds, it scrolls by default. No space or comments are allowed
+           before the closing tag. -->
+      <textarea id="input" autofocus="[[autofocus]]" rows="[[rows]]"
           value="{{value::input}}" aria-label$="[[label]]"
           on-focus="onInputFocusChange_" on-blur="onInputFocusChange_"
           on-change="onInputChange_"></textarea>
diff --git a/chrome/browser/resources/settings/controls/settings_textarea.js b/chrome/browser/resources/settings/controls/settings_textarea.js
index a7faab3..1def7671 100644
--- a/chrome/browser/resources/settings/controls/settings_textarea.js
+++ b/chrome/browser/resources/settings/controls/settings_textarea.js
@@ -10,17 +10,34 @@
   is: 'settings-textarea',
 
   properties: {
+    /**
+       Whether the text area should automatically get focus when the page
+       loads.
+     */
     autofocus: {
       type: Boolean,
       value: false,
       reflectToAttribute: true,
     },
 
+    /** Number of rows (lines) of the text area. */
+    rows: {
+      type: Number,
+      value: 3,
+      reflectToAttribute: true,
+    },
+
+    /** Caption of the text area. */
     label: {
       type: String,
       value: '',
     },
 
+    /**
+     * Text inside the text area. If the text exceeds the bounds of the text
+     * area, i.e. if it has more than |rows| lines, a scrollbar is shown by
+     * default.
+     */
     value: {
       type: String,
       value: '',
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
index 580c567..a380b921 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
@@ -31,7 +31,7 @@
 
 <dom-module id="settings-internet-detail-page">
   <template>
-    <style include="internet-shared settings-shared iron-flex">
+    <style include="internet-shared iron-flex">
       :host {
         padding-bottom: 40px;
       }
@@ -65,10 +65,6 @@
       paper-spinner-lite {
         @apply --cr-icon-height-width;
       }
-      .warning {
-          color: var(--cr-secondary-text-color);
-          margin-inline-start: var(--settings-controlled-by-spacing);
-      }
     </style>
     <!-- Title section: Icon + name + connection state. -->
     <div id="titleDiv" class="settings-box first">
@@ -187,15 +183,6 @@
             pref="{{autoConnect_}}"
             label="[[getAutoConnectToggleLabel_(networkProperties_)]]">
         </settings-toggle-button>
-        <!-- Hidden Network Warning -->
-        <template is="dom-if"
-            if="[[showHiddenNetworkWarning_(autoConnect_, networkProperties_)]]"
-            restamp>
-          <div class="warning">
-            <iron-icon icon="cr:warning"></iron-icon>
-            [[i18n('hiddenNetworkWarning')]]
-          </div>
-        </template>
       </template>
       <!-- Always-on VPN. -->
       <template is="dom-if"
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.js b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
index 18d8fafd..090c91a9 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
@@ -957,16 +957,6 @@
   },
 
   /**
-   * @return {boolean}
-   * @private
-   */
-  showHiddenNetworkWarning_: function() {
-    return !!this.autoConnect_ && !!this.autoConnect_.value &&
-        !!this.networkProperties_ && !!this.networkProperties_.WiFi &&
-        !!CrOnc.getActiveValue(this.networkProperties_.WiFi.HiddenSSID);
-  },
-
-  /**
    * Event triggered for elements associated with network properties.
    * @param {!CustomEvent<!{
    *     field: string,
diff --git a/chrome/browser/resources/settings/os_settings_manifest.json b/chrome/browser/resources/settings/os_settings_manifest.json
new file mode 100644
index 0000000..17d5330
--- /dev/null
+++ b/chrome/browser/resources/settings/os_settings_manifest.json
@@ -0,0 +1,13 @@
+{
+  "name": "Settings",
+  "display": "standalone",
+  "icons": [
+    {
+      "src": "icon-192.png",
+      "sizes": "192x192",
+      "type": "image/png"
+    }
+  ],
+  "start_url": "/",
+  "theme_color": "#F8F9FA"
+}
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd
index 819d51d4..4f553c9 100644
--- a/chrome/browser/resources/settings/os_settings_resources.grd
+++ b/chrome/browser/resources/settings/os_settings_resources.grd
@@ -40,7 +40,7 @@
                  file="a11y_page/tts_subpage.html"
                  type="chrome_html" />
       <structure name="IDR_OS_SETTINGS_MANIFEST"
-                 file="manifest.json"
+                 file="os_settings_manifest.json"
                  type="chrome_html" />
       <structure name="IDR_OS_SETTINGS_ADD_SITE_DIALOG_HTML"
                  file="site_settings/add_site_dialog.html"
diff --git a/chrome/browser/resources/settings/os_settings_resources_vulcanized.grd b/chrome/browser/resources/settings/os_settings_resources_vulcanized.grd
index 04aae4ac..24bcdcc 100644
--- a/chrome/browser/resources/settings/os_settings_resources_vulcanized.grd
+++ b/chrome/browser/resources/settings/os_settings_resources_vulcanized.grd
@@ -38,7 +38,10 @@
                flattenhtml="true"
                type="BINDATA"
                compress="gzip" />
-      <include name="IDR_OS_SETTINGS_MANIFEST" file="manifest.json" type="BINDATA" compress="gzip" />
+      <include name="IDR_OS_SETTINGS_MANIFEST"
+               file="os_settings_manifest.json"
+               type="BINDATA"
+               compress="gzip" />
     </includes>
   </release>
 </grit>
diff --git a/chrome/browser/resources/settings/people_page/BUILD.gn b/chrome/browser/resources/settings/people_page/BUILD.gn
index 68f69699..799bbfa9 100644
--- a/chrome/browser/resources/settings/people_page/BUILD.gn
+++ b/chrome/browser/resources/settings/people_page/BUILD.gn
@@ -129,12 +129,14 @@
 js_library("kerberos_add_account_dialog") {
   deps = [
     ":kerberos_accounts_browser_proxy",
+    "//chrome/browser/resources/settings/controls:settings_textarea",
     "//ui/webui/resources/cr_elements/cr_input:cr_input",
     "//ui/webui/resources/js:cr",
     "//ui/webui/resources/js:i18n_behavior",
     "//ui/webui/resources/js:web_ui_listener_behavior",
   ]
 }
+
 js_library("lock_screen") {
   deps = [
     ":fingerprint_browser_proxy",
diff --git a/chrome/browser/resources/settings/people_page/kerberos_accounts.html b/chrome/browser/resources/settings/people_page/kerberos_accounts.html
index e658441d..9d555623 100644
--- a/chrome/browser/resources/settings/people_page/kerberos_accounts.html
+++ b/chrome/browser/resources/settings/people_page/kerberos_accounts.html
@@ -107,6 +107,9 @@
       <div class="clear settings-box"></div>
 
       <cr-action-menu>
+        <button class="dropdown-item" on-click="onRefreshNowClick_">
+          $i18n{kerberosAccountsRefreshNowLabel}
+        </button>
         <button class="dropdown-item" on-click="onSetAsActiveAccountClick_">
           $i18n{kerberosAccountsSetAsActiveAccountLabel}
         </button>
diff --git a/chrome/browser/resources/settings/people_page/kerberos_accounts.js b/chrome/browser/resources/settings/people_page/kerberos_accounts.js
index 96660b6..7bbb9be 100644
--- a/chrome/browser/resources/settings/people_page/kerberos_accounts.js
+++ b/chrome/browser/resources/settings/people_page/kerberos_accounts.js
@@ -86,11 +86,11 @@
   /** @private */
   onAddAccountDialogClosed_: function() {
     this.showAddAccountDialog_ = false;
+    // In case it was opened by the 'Refresh now' action menu.
+    this.closeActionMenu_();
   },
 
-  /**
-   * @private
-   */
+  /** @private */
   refreshAccounts_: function() {
     this.browserProxy_.getAccounts().then(accounts => {
       this.accounts_ = accounts;
@@ -139,6 +139,14 @@
   },
 
   /**
+   * Opens the reauth dialog for |this.selectedAccount_|.
+   * @private
+   */
+  onRefreshNowClick_: function() {
+    this.showAddAccountDialog_ = true;
+  },
+
+  /**
    * @param {boolean} isActive Whether a Kerberos account is active.
    * @return {string} Localized label for the active/inactive state.
    * @private
diff --git a/chrome/browser/resources/settings/people_page/kerberos_accounts_browser_proxy.js b/chrome/browser/resources/settings/people_page/kerberos_accounts_browser_proxy.js
index 68c3250f..1969db9 100644
--- a/chrome/browser/resources/settings/people_page/kerberos_accounts_browser_proxy.js
+++ b/chrome/browser/resources/settings/people_page/kerberos_accounts_browser_proxy.js
@@ -13,6 +13,7 @@
  * Information for a Chrome OS Kerberos account.
  * @typedef {{
  *   principalName: string,
+ *   config: string,
  *   isSignedIn: boolean,
  *   isActive: boolean,
  *   hasRememberedPassword: boolean,
@@ -63,9 +64,12 @@
      * @param {string} principalName Kerberos principal (user@realm.com).
      * @param {string} password Account password.
      * @param {boolean} rememberPassword Whether to store the password.
+     * @param {string} config Kerberos configuration.
+     * @param {boolean} allowExisting Whether existing accounts may be updated.
      * @return {!Promise<!settings.KerberosErrorType>}
      */
-    addAccount(principalName, password, rememberPassword) {}
+    addAccount(
+        principalName, password, rememberPassword, config, allowExisting) {}
 
     /**
      * Removes |account| from the set of Kerberos accounts.
@@ -91,9 +95,11 @@
     }
 
     /** @override */
-    addAccount(principalName, password, rememberPassword) {
+    addAccount(
+        principalName, password, rememberPassword, config, allowExisting) {
       return cr.sendWithPromise(
-          'addKerberosAccount', principalName, password, rememberPassword);
+          'addKerberosAccount', principalName, password, rememberPassword,
+          config, allowExisting);
     }
 
     /** @override */
diff --git a/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.html b/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.html
index 93e8aa6..86a6719 100644
--- a/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.html
+++ b/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.html
@@ -6,28 +6,35 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
+<link rel="import" href="chrome://resources/html/action_link.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/html/load_time_data.html">
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="import" href="../controls/settings_textarea.html">
 <link rel="import" href="kerberos_accounts_browser_proxy.html">
 
 <dom-module id="kerberos-add-account-dialog">
   <template>
-    <style>
+    <style include="action-link">
       .label {
         @apply --cr-form-field-label;
       }
 
-      #credentials > cr-input:not(:last-child) {
+      #credentials > *:not(:last-child) {
         margin-bottom: var(--cr-form-field-bottom-spacing);
       }
 
       #general-error-container {
         height: 48px;
       }
+
+      #desc {
+        margin-bottom: 32px;
+      }
     </style>
-    <cr-dialog id="dialog">
+
+    <cr-dialog id="addDialog" hidden="[[showAdvancedConfig_]]">
       <div slot="title">$i18n{addKerberosAccount}</div>
       <div slot="body" spellcheck="false">
         <div id="general-error-container">
@@ -50,6 +57,10 @@
           <cr-checkbox id="rememberPassword" checked="{{rememberPassword_}}">
             $i18n{addKerberosAccountRememberPassword}
           </cr-checkbox>
+          <a is="action-link" id="advancedConfigButton"
+              on-click="onAdvancedConfigClick_">
+            $i18n{kerberosAdvancedConfigLabel}
+          </a>
         </div>
       </div>
       <div slot="button-container">
@@ -62,6 +73,27 @@
         </cr-button>
       </div>
     </cr-dialog>
+
+    <template is="dom-if" if="[[showAdvancedConfig_]]" restamp>
+      <cr-dialog id="advancedConfigDialog" on-close=onAdvancedConfigClose_>
+        <div slot="title">$i18n{kerberosAdvancedConfigTitle}</div>
+        <div slot="body">
+          <div id="desc">$i18n{kerberosAdvancedConfigDesc}</div>
+          <settings-textarea id="config" label="$i18n{kerberosConfig}"
+              value="{{editableConfig_}}" rows=12 spellcheck="false">
+          </settings-textarea>
+        </div>
+        <div slot="button-container">
+          <paper-button class="cancel-button"
+              on-click="onAdvancedConfigCancel_">
+            $i18n{cancel}
+          </paper-button>
+          <paper-button class="action-button" on-click="onAdvancedConfigSave_">
+            $i18n{save}
+          </paper-button>
+        </div>
+      </cr-dialog>
+    </template>
   </template>
   <script src="kerberos_add_account_dialog.js"></script>
 </dom-module>
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.js b/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.js
index e5c914f..e66c98be 100644
--- a/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.js
+++ b/chrome/browser/resources/settings/people_page/kerberos_add_account_dialog.js
@@ -32,6 +32,16 @@
       value: '',
     },
 
+    /**
+     * Current configuration in the Advanced Config dialog. Propagates to
+     * |config| only if 'Save' button is pressed.
+     * @private {string}
+     */
+    editableConfig_: {
+      type: String,
+      value: '',
+    },
+
     /** @private */
     rememberPassword_: {
       type: Boolean,
@@ -61,20 +71,23 @@
       type: Boolean,
       value: false,
     },
+
+    /** @private */
+    showAdvancedConfig_: {
+      type: Boolean,
+      value: false,
+    },
   },
 
-  /** @private {?settings.KerberosAccountsBrowserProxy} */
-  browserProxy_: null,
-
-  /** @private {!settings.KerberosErrorType} */
-  lastError_: settings.KerberosErrorType.kNone,
-
   /** @private {boolean} */
   useRememberedPassword_: false,
 
+  /** @private {string} */
+  config_: '',
+
   /** @override */
   attached: function() {
-    this.$.dialog.showModal();
+    this.$.addDialog.showModal();
 
     if (this.presetAccount) {
       // Preset username and make UI read-only.
@@ -94,12 +107,17 @@
         this.rememberPassword_ = true;
         this.useRememberedPassword_ = true;
       }
+
+      this.config_ = this.presetAccount.config;
+    } else {
+      // Set a default configuration.
+      this.config_ = loadTimeData.getString('defaultKerberosConfig');
     }
   },
 
   /** @private */
   onCancel_: function() {
-    this.$.dialog.cancel();
+    this.$.addDialog.cancel();
   },
 
   /** @private */
@@ -110,14 +128,19 @@
     // An empty password triggers the Kerberos daemon to use the remembered one.
     const passwordToSubmit = this.useRememberedPassword_ ? '' : this.password_;
 
+    // For new accounts (no preset), bail if the account already exists.
+    const allowExisting = !!this.presetAccount;
+
     settings.KerberosAccountsBrowserProxyImpl.getInstance()
-        .addAccount(this.username_, passwordToSubmit, this.rememberPassword_)
+        .addAccount(
+            this.username_, passwordToSubmit, this.rememberPassword_,
+            this.config_, allowExisting)
         .then(error => {
           this.inProgress_ = false;
 
           // Success case. Close dialog.
           if (error == settings.KerberosErrorType.kNone) {
-            this.$.dialog.close();
+            this.$.addDialog.close();
             return;
           }
 
@@ -133,13 +156,44 @@
     this.useRememberedPassword_ = false;
   },
 
+  /** @private */
+  onAdvancedConfigClick_: function() {
+    // Keep a copy of the config in case the user cancels.
+    this.editableConfig_ = this.config_;
+    this.showAdvancedConfig_ = true;
+    Polymer.dom.flush();
+    this.$$('#advancedConfigDialog').showModal();
+  },
+
+  /** @private */
+  onAdvancedConfigCancel_: function() {
+    this.showAdvancedConfig_ = false;
+    this.$$('#advancedConfigDialog').cancel();
+  },
+
+  /** @private */
+  onAdvancedConfigSave_: function() {
+    this.showAdvancedConfig_ = false;
+    this.config_ = this.editableConfig_;
+    this.$$('#advancedConfigDialog').close();
+  },
+
+  onAdvancedConfigClose_: function(event) {
+    // Note: 'Esc' doesn't trigger onAdvancedConfigCancel_() and some tests
+    // that trigger onAdvancedConfigCancel_() don't trigger this for some
+    // reason, hence this is needed here and above.
+    this.showAdvancedConfig_ = false;
+
+    // Since this is a sub-dialog, prevent event from bubbling up. Otherwise,
+    // it might cause the add-dialog to be closed.
+    event.stopPropagation();
+  },
+
   /**
    * @param {!settings.KerberosErrorType} error Current error enum
    * @private
    */
   updateErrorMessages_: function(error) {
-    this.lastError_ = error;
-
     this.generalErrorText_ = '';
     this.usernameErrorText_ = '';
     this.passwordErrorText_ = '';
@@ -157,6 +211,10 @@
       case settings.KerberosErrorType.kBadPrincipal:
         this.usernameErrorText_ = this.i18n('kerberosErrorUsernameUnknown');
         break;
+      case settings.KerberosErrorType.kDuplicatePrincipalName:
+        this.usernameErrorText_ =
+            this.i18n('kerberosErrorDuplicatePrincipalName');
+        break;
       case settings.KerberosErrorType.kContactingKdcFailed:
         this.usernameErrorText_ = this.i18n('kerberosErrorContactingServer');
         break;
diff --git a/chrome/browser/resources/signin/sync_confirmation/sync_disabled_confirmation.html b/chrome/browser/resources/signin/sync_confirmation/sync_disabled_confirmation.html
index 77cac079..0ed1aa72 100644
--- a/chrome/browser/resources/signin/sync_confirmation/sync_disabled_confirmation.html
+++ b/chrome/browser/resources/signin/sync_confirmation/sync_disabled_confirmation.html
@@ -48,7 +48,7 @@
     -->
     <div class="container">
       <div class="top-title-bar" consent-description>
-        $i18n{syncConfirmationTitle}
+        $i18n{syncDisabledConfirmationTitle}
       </div>
       <div class="details" id="syncDisabledDetails">
         <div class="body text" consent-description>
@@ -58,10 +58,10 @@
       <div class="action-container">
         <paper-button class="action-button" id="confirmButton"
             consent-confirmation>
-          $i18n{syncConfirmationConfirmLabel}
+          $i18n{syncDisabledConfirmationConfirmLabel}
         </paper-button>
         <paper-button id="undoButton">
-          $i18n{syncConfirmationUndoLabel}
+          $i18n{syncDisabledConfirmationUndoLabel}
         </paper-button>
       </div>
     </div>
diff --git a/chrome/browser/search_engines/template_url_android.h b/chrome/browser/search_engines/template_url_android.h
deleted file mode 100644
index 61bf2e8..0000000
--- a/chrome/browser/search_engines/template_url_android.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_ANDROID_H_
-#define CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_ANDROID_H_
-
-#include "base/android/jni_weak_ref.h"
-#include "base/android/scoped_java_ref.h"
-#include "components/search_engines/template_url.h"
-
-// Android wrapper of the TemplateUrl which provides access for the Java
-// layer.
-class TemplateUrlAndroid;
-
-base::android::ScopedJavaLocalRef<jobject> CreateTemplateUrlAndroid(
-    JNIEnv* env,
-    const TemplateURL* template_url);
-
-#endif  // CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_ANDROID_H_
diff --git a/chrome/browser/search_engines/template_url_service_factory_android.cc b/chrome/browser/search_engines/template_url_service_factory_android.cc
new file mode 100644
index 0000000..0332bbf
--- /dev/null
+++ b/chrome/browser/search_engines/template_url_service_factory_android.cc
@@ -0,0 +1,59 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "components/search_engines/template_url_service.h"
+#include "components/search_provider_logos/features.h"
+#include "components/search_provider_logos/switches.h"
+#include "jni/TemplateUrlServiceFactory_jni.h"
+
+namespace {
+Profile* GetOriginalProfile() {
+  return ProfileManager::GetActiveUserProfile()->GetOriginalProfile();
+}
+}  // namespace
+
+static TemplateURLService* GetTemplateUrlService() {
+  return TemplateURLServiceFactory::GetForProfile(GetOriginalProfile());
+}
+
+static base::android::ScopedJavaLocalRef<jobject>
+JNI_TemplateUrlServiceFactory_GetTemplateUrlService(JNIEnv* env) {
+  return GetTemplateUrlService()->GetJavaObject();
+}
+
+static jboolean IsDefaultSearchEngineGoogle(JNIEnv* env) {
+  const TemplateURL* default_search_provider =
+      GetTemplateUrlService()->GetDefaultSearchProvider();
+  return default_search_provider &&
+         default_search_provider->url_ref().HasGoogleBaseURLs(
+             GetTemplateUrlService()->search_terms_data());
+}
+
+static jboolean JNI_TemplateUrlServiceFactory_DoesDefaultSearchEngineHaveLogo(
+    JNIEnv* env) {
+  // |kSearchProviderLogoURL| applies to all search engines (Google or
+  // third-party).
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          search_provider_logos::switches::kSearchProviderLogoURL)) {
+    return true;
+  }
+
+  // Google always has a logo.
+  if (IsDefaultSearchEngineGoogle(env))
+    return true;
+
+  // Third-party search engines can have a doodle specified via the command
+  // line, or a static logo or doodle from the TemplateURLService.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          search_provider_logos::switches::kThirdPartyDoodleURL)) {
+    return true;
+  }
+  const TemplateURL* default_search_provider =
+      GetTemplateUrlService()->GetDefaultSearchProvider();
+  return default_search_provider &&
+         (default_search_provider->doodle_url().is_valid() ||
+          default_search_provider->logo_url().is_valid());
+}
diff --git a/chrome/browser/service_process/service_process_control_browsertest.cc b/chrome/browser/service_process/service_process_control_browsertest.cc
index 6f04053..06a5af3 100644
--- a/chrome/browser/service_process/service_process_control_browsertest.cc
+++ b/chrome/browser/service_process/service_process_control_browsertest.cc
@@ -90,9 +90,9 @@
     // point to a bundle so that the service process has an Info.plist.
     base::FilePath exe_path;
     ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &exe_path));
-    exe_path = exe_path.DirName()
+    exe_path = exe_path.Append(chrome::kBrowserProcessExecutablePath)
                    .DirName()
-                   .Append("Contents")
+                   .DirName()
                    .Append("Frameworks")
                    .Append(chrome::kFrameworkName)
                    .Append("Versions")
diff --git a/chrome/browser/signin/identity_manager_factory.cc b/chrome/browser/signin/identity_manager_factory.cc
index 98c576a..afcbb316 100644
--- a/chrome/browser/signin/identity_manager_factory.cc
+++ b/chrome/browser/signin/identity_manager_factory.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/signin/identity_manager_factory.h"
 
+#include <memory>
 #include <utility>
 
 #include "build/build_config.h"
@@ -18,7 +19,9 @@
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
 #include "components/signin/core/browser/identity_manager_wrapper.h"
-#include "components/signin/core/browser/primary_account_policy_manager.h"
+#include "components/signin/core/browser/primary_account_manager.h"
+#include "components/signin/core/browser/primary_account_policy_manager_impl.h"
+#include "components/signin/core/browser/signin_client.h"
 #include "services/identity/public/cpp/accounts_cookie_mutator.h"
 #include "services/identity/public/cpp/accounts_cookie_mutator_impl.h"
 #include "services/identity/public/cpp/accounts_mutator.h"
@@ -77,15 +80,14 @@
   std::unique_ptr<PrimaryAccountManager> primary_account_manager;
   SigninClient* client =
       ChromeSigninClientFactory::GetInstance()->GetForProfile(profile);
-#if defined(OS_CHROMEOS)
+  std::unique_ptr<PrimaryAccountPolicyManager> policy_manager;
+#if !defined(OS_CHROMEOS)
+  policy_manager = std::make_unique<PrimaryAccountPolicyManagerImpl>(client);
+#endif
   primary_account_manager = std::make_unique<PrimaryAccountManager>(
       client, token_service, account_tracker_service,
-      AccountConsistencyModeManager::GetMethodForProfile(profile));
-#else
-  primary_account_manager = std::make_unique<PrimaryAccountPolicyManager>(
-      client, token_service, account_tracker_service,
-      AccountConsistencyModeManager::GetMethodForProfile(profile));
-#endif
+      AccountConsistencyModeManager::GetMethodForProfile(profile),
+      std::move(policy_manager));
   primary_account_manager->Initialize(g_browser_process->local_state());
   return primary_account_manager;
 }
diff --git a/chrome/browser/supervised_user/supervised_user_settings_service_factory.cc b/chrome/browser/supervised_user/supervised_user_settings_service_factory.cc
index 8e14e827..5f85a90 100644
--- a/chrome/browser/supervised_user/supervised_user_settings_service_factory.cc
+++ b/chrome/browser/supervised_user/supervised_user_settings_service_factory.cc
@@ -37,7 +37,5 @@
 SimpleFactoryKey* SupervisedUserSettingsServiceFactory::GetKeyToUse(
     SimpleFactoryKey* key) const {
   ProfileKey* profile_key = ProfileKey::FromSimpleFactoryKey(key);
-  if (profile_key->IsOffTheRecord())
-    return profile_key->GetOriginalKey();
-  return profile_key;
+  return profile_key->GetOriginalKey();
 }
diff --git a/chrome/browser/ui/app_list/extension_app_utils.cc b/chrome/browser/ui/app_list/extension_app_utils.cc
index 9affea2..002ddce 100644
--- a/chrome/browser/ui/app_list/extension_app_utils.cc
+++ b/chrome/browser/ui/app_list/extension_app_utils.cc
@@ -16,6 +16,11 @@
 #include "ui/views/controls/menu/menu_config.h"
 #include "ui/views/vector_icons.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.h"
+#endif
+
 namespace app_list {
 
 namespace {
@@ -27,6 +32,26 @@
 
 bool ShouldShowInLauncher(const extensions::Extension* extension,
                           content::BrowserContext* context) {
+  // TODO(crbug.com/971029): Make this a per System Web App property that is
+  // accessible by querying the SystemWebAppManager.
+#if defined(OS_CHROMEOS)
+  Profile* profile = Profile::FromBrowserContext(context);
+  // These System Web Apps should not show in the launcher as they are added
+  // as internal apps.
+  web_app::SystemAppType hidden_system_web_apps[] = {
+      // TODO(crbug.com/836128): Remove this once OS Settings is launched, and
+      // permanently migrate OS Settings from an internal app to a full System
+      // Web App.
+      web_app::SystemAppType::SETTINGS,
+  };
+  for (auto app_type : hidden_system_web_apps) {
+    if (extension->id() ==
+        web_app::GetAppIdForSystemWebApp(profile, app_type)) {
+      return false;
+    }
+  }
+#endif
+
   return !HideInLauncherById(extension->id()) &&
          chromeos::DemoSession::ShouldDisplayInAppLauncher(extension->id()) &&
          extensions::ui_util::ShouldDisplayInAppLauncher(extension, context);
diff --git a/chrome/browser/ui/ash/chrome_new_window_client.cc b/chrome/browser/ui/ash/chrome_new_window_client.cc
index cadbc00..60920e5 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/sessions/tab_restore_service_factory.h"
 #include "chrome/browser/tab_contents/tab_util.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -40,6 +41,7 @@
 #include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/common/webui_url_constants.h"
+#include "components/arc/arc_util.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/sessions/core/tab_restore_service.h"
 #include "components/sessions/core/tab_restore_service_observer.h"
@@ -476,7 +478,23 @@
     arc::mojom::IntentHelperHost::OnOpenCustomTabCallback callback) {
   GURL url_to_open = ConvertArcUrlToExternalFileUrlIfNeeded(url);
   Profile* profile = ProfileManager::GetActiveUserProfile();
-  auto custom_tab = ash::ArcCustomTab::Create(task_id, surface_id, top_margin);
+
+  aura::Window* arc_window = nullptr;
+  for (auto* window : ChromeLauncherController::instance()->GetArcWindows()) {
+    if (arc::GetWindowTaskId(window) == task_id) {
+      arc_window = window;
+      break;
+    }
+  }
+  if (!arc_window) {
+    LOG(ERROR) << "No ARC window with the specified task ID " << task_id;
+    std::move(callback).Run(
+        CustomTabSessionImpl::Create(profile, url, nullptr));
+    return;
+  }
+
+  auto custom_tab =
+      ash::ArcCustomTab::Create(arc_window, surface_id, top_margin);
   std::move(callback).Run(
       CustomTabSessionImpl::Create(profile, url, std::move(custom_tab)));
 }
diff --git a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
index d94fc04..6db89e1 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
@@ -15,6 +15,8 @@
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chrome/browser/ui/settings_window_manager_observer_chromeos.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/web_applications/system_web_app_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/account_id/account_id.h"
 #include "components/session_manager/core/session_manager.h"
@@ -172,6 +174,11 @@
     int new_settings_count_ = 0;
   } observer;
 
+  // Install the Settings App.
+  web_app::WebAppProvider::Get(browser()->profile())
+      ->system_web_app_manager()
+      .InstallSystemAppsForTesting();
+
   auto* settings = chrome::SettingsWindowManager::GetInstance();
   settings->AddObserver(&observer);
 
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
index 486958b..7f98768b 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
@@ -72,6 +72,10 @@
 
   int active_task_id() const { return active_task_id_; }
 
+  const std::vector<aura::Window*>& GetObservedWindows() {
+    return observed_windows_;
+  }
+
  private:
   class AppWindowInfo;
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 1e0185f..0df23da 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -8,6 +8,7 @@
 #include <set>
 #include <utility>
 
+#include "ash/public/cpp/app_types.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/multi_user_window_manager.h"
 #include "ash/public/cpp/shelf_item.h"
@@ -72,6 +73,7 @@
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "components/account_id/account_id.h"
 #include "components/arc/arc_prefs.h"
+#include "components/arc/arc_util.h"
 #include "components/favicon/content/content_favicon_driver.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/sync_preferences/pref_service_syncable.h"
@@ -80,6 +82,7 @@
 #include "content/public/common/service_manager_connection.h"
 #include "extensions/common/extension.h"
 #include "services/service_manager/public/cpp/connector.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -261,8 +264,12 @@
         new ExtensionAppWindowLauncherController(this));
   }
   app_window_controllers_.push_back(std::move(extension_app_window_controller));
-  app_window_controllers_.push_back(
-      std::make_unique<ArcAppWindowLauncherController>(this));
+
+  auto arc_app_window_controller =
+      std::make_unique<ArcAppWindowLauncherController>(this);
+  arc_app_window_controller_ = arc_app_window_controller.get();
+  app_window_controllers_.push_back(std::move(arc_app_window_controller));
+
   if (crostini::IsCrostiniUIAllowedForProfile(profile)) {
     std::unique_ptr<CrostiniAppWindowShelfController> crostini_controller =
         std::make_unique<CrostiniAppWindowShelfController>(this);
@@ -278,6 +285,7 @@
   browser_status_monitor_.reset();
 
   // Reset the app window controllers here since it has a weak pointer to this.
+  arc_app_window_controller_ = nullptr;
   app_window_controllers_.clear();
 
   // Destroy the ShelfSpinnerController before clearing delegates.
@@ -605,6 +613,16 @@
   return AppShortcutLauncherItemController::GetRunningApplications(app_id);
 }
 
+std::vector<aura::Window*> ChromeLauncherController::GetArcWindows() {
+  std::vector<aura::Window*> windows =
+      arc_app_window_controller_->GetObservedWindows();
+  std::vector<aura::Window*> arc_windows;
+  std::copy_if(windows.begin(), windows.end(),
+               std::inserter(arc_windows, arc_windows.end()),
+               [](aura::Window* w) { return arc::IsArcAppWindow(w); });
+  return arc_windows;
+}
+
 void ChromeLauncherController::ActivateShellApp(const std::string& app_id,
                                                 int window_index) {
   const ash::ShelfItem* item = GetItem(ash::ShelfID(app_id));
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
index e9c5ae0..99c6dd1 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -18,6 +18,7 @@
 #include "chrome/browser/ui/app_icon_loader_delegate.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
 #include "chrome/browser/ui/app_list/app_sync_ui_state_observer.h"
+#include "chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.h"
 #include "chrome/browser/ui/ash/launcher/discover_window_observer.h"
 #include "chrome/browser/ui/ash/launcher/launcher_app_updater.h"
@@ -179,6 +180,9 @@
   std::vector<content::WebContents*> GetV1ApplicationsFromAppId(
       const std::string& app_id);
 
+  // Get the list of all ARC app windows.
+  std::vector<aura::Window*> GetArcWindows();
+
   // Activates a specified shell application by app id and window index.
   void ActivateShellApp(const std::string& app_id, int window_index);
 
@@ -397,6 +401,9 @@
   std::vector<std::unique_ptr<AppWindowLauncherController>>
       app_window_controllers_;
 
+  // Pointer to the ARC app window controller owned by app_window_controllers_.
+  ArcAppWindowLauncherController* arc_app_window_controller_ = nullptr;
+
   // Used to handle app load/unload events.
   std::vector<std::unique_ptr<LauncherAppUpdater>> app_updaters_;
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
index ae2edff..1323b8e 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -53,6 +53,8 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/test/test_app_window_icon_observer.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "chrome/browser/web_applications/system_web_app_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -1731,6 +1733,10 @@
 
 // Ensure opening settings and task manager windows create new shelf items.
 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, SettingsAndTaskManagerWindows) {
+  // Install the Settings App.
+  web_app::WebAppProvider::Get(browser()->profile())
+      ->system_web_app_manager()
+      .InstallSystemAppsForTesting();
   chrome::SettingsWindowManager* settings_manager =
       chrome::SettingsWindowManager::GetInstance();
 
diff --git a/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc b/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
index b276528..4b0a321 100644
--- a/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
+++ b/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
@@ -17,6 +17,8 @@
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/web_applications/system_web_app_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -38,6 +40,10 @@
 
 // This test verifies that the settings page is opened in a new browser window.
 IN_PROC_BROWSER_TEST_F(BrowserNavigatorTestChromeOS, NavigateToSettings) {
+  // Install the Settings App.
+  web_app::WebAppProvider::Get(browser()->profile())
+      ->system_web_app_manager()
+      .InstallSystemAppsForTesting();
   GURL old_url = browser()->tab_strip_model()->GetActiveWebContents()->GetURL();
   {
     content::WindowedNotificationObserver observer(
diff --git a/chrome/browser/ui/content_settings/framebust_block_browsertest.cc b/chrome/browser/ui/content_settings/framebust_block_browsertest.cc
index ebc5e5c..1965154 100644
--- a/chrome/browser/ui/content_settings/framebust_block_browsertest.cc
+++ b/chrome/browser/ui/content_settings/framebust_block_browsertest.cc
@@ -37,6 +37,11 @@
 #include "ui/events/event_constants.h"
 #include "url/gurl.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/web_applications/system_web_app_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#endif
+
 namespace {
 
 const int kAllowRadioButtonIndex = 0;
@@ -206,6 +211,12 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FramebustBlockBrowserTest, ManageButtonClicked) {
+#if defined(OS_CHROMEOS)
+  web_app::WebAppProvider::Get(browser()->profile())
+      ->system_web_app_manager()
+      .InstallSystemAppsForTesting();
+#endif
+
   const GURL url = embedded_test_server()->GetURL("/iframe.html");
   ui_test_utils::NavigateToURL(browser(), url);
 
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
index c77f594..90f205de 100644
--- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -27,6 +27,8 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/web_applications/system_web_app_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -1642,6 +1644,11 @@
   OmniboxView* omnibox_view = nullptr;
   ASSERT_NO_FATAL_FAILURE(GetOmniboxView(&omnibox_view));
 #if defined(OS_CHROMEOS)
+  // Install the Settings App.
+  web_app::WebAppProvider::Get(browser()->profile())
+      ->system_web_app_manager()
+      .InstallSystemAppsForTesting();
+
   EXPECT_FALSE(
       chrome::SettingsWindowManager::GetInstance()->FindBrowserForProfile(
           browser()->profile()));
diff --git a/chrome/browser/ui/settings_window_manager_browsertest_chromeos.cc b/chrome/browser/ui/settings_window_manager_browsertest_chromeos.cc
index 5477afae..7c5179f 100644
--- a/chrome/browser/ui/settings_window_manager_browsertest_chromeos.cc
+++ b/chrome/browser/ui/settings_window_manager_browsertest_chromeos.cc
@@ -63,6 +63,7 @@
     if (!EnableSystemWebApps())
       return;
 
+    // Install the Settings App.
     web_app::WebAppProvider::Get(browser()->profile())
         ->system_web_app_manager()
         .InstallSystemAppsForTesting();
diff --git a/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.cc b/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.cc
index b53229e..a0998d9c 100644
--- a/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.cc
+++ b/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/ui/tab_sharing/tab_sharing_ui.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/infobars/core/infobar.h"
+#include "components/vector_icons/vector_icons.h"
 #include "ui/base/l10n/l10n_util.h"
 
 // static
@@ -76,3 +77,7 @@
 bool TabSharingInfoBarDelegate::IsCloseable() const {
   return false;
 }
+
+const gfx::VectorIcon& TabSharingInfoBarDelegate::GetVectorIcon() const {
+  return vector_icons::kScreenShareIcon;
+}
diff --git a/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.h b/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.h
index c5f13f9..984f7b3 100644
--- a/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.h
+++ b/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.h
@@ -44,6 +44,7 @@
   bool Accept() override;
   bool Cancel() override;
   bool IsCloseable() const override;
+  const gfx::VectorIcon& GetVectorIcon() const override;
 
   const base::string16 shared_tab_name_;
   const base::string16 app_name_;
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
index 31f6e8e..281c2dd 100644
--- a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
@@ -83,6 +83,8 @@
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
+#include "chrome/browser/web_applications/system_web_app_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
 #endif
 
 using base::Bucket;
@@ -161,6 +163,11 @@
         IdentityManagerFactory::GetForProfile(browser()->profile())
             ->GetPrimaryAccountInfo();
     username = info.email;
+
+    // Install the Settings App.
+    web_app::WebAppProvider::Get(browser()->profile())
+        ->system_web_app_manager()
+        .InstallSystemAppsForTesting();
 #endif
     if (username.empty())
       username = "user@gmail.com";
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc
index ad287ff6..058eb5b 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc
@@ -27,9 +27,13 @@
 
 class BookmarkBubbleViewTest : public BrowserWithTestWindowTest {
  public:
+  // The test executes the UI code for displaying a window that should be
+  // executed on the UI thread. The test also hits the networking code that
+  // fails without the IO thread. We pass the REAL_IO_THREAD option to run UI
+  // and IO tasks on separate threads.
   BookmarkBubbleViewTest()
       : BrowserWithTestWindowTest(
-            content::TestBrowserThreadBundle::IO_MAINLOOP) {}
+            content::TestBrowserThreadBundle::REAL_IO_THREAD) {}
 
   // testing::Test:
   void SetUp() override {
@@ -81,14 +85,7 @@
 }
 
 // Verifies that the sync promo is displayed for a user that is not signed in.
-#if defined(OS_CHROMEOS)
-// TODO(https://crbug.com/966220): Consistently failing on trybot.
-#define MAYBE_SyncPromoNotSignedIn DISABLED_SyncPromoNotSignedIn
-#else
-#define MAYBE_SyncPromoNotSignedIn SyncPromoNotSignedIn
-#endif  // defined(OS_CHROMEOS)
-
-TEST_F(BookmarkBubbleViewTest, MAYBE_SyncPromoNotSignedIn) {
+TEST_F(BookmarkBubbleViewTest, SyncPromoNotSignedIn) {
   CreateBubbleView();
   std::unique_ptr<views::View> footnote = CreateFootnoteView();
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/views/crostini/crostini_installer_view.cc b/chrome/browser/ui/views/crostini/crostini_installer_view.cc
index 30e10762..63f57665 100644
--- a/chrome/browser/ui/views/crostini/crostini_installer_view.cc
+++ b/chrome/browser/ui/views/crostini/crostini_installer_view.cc
@@ -217,7 +217,6 @@
   }
 
   UpdateState(State::INSTALL_START);
-  profile_->GetPrefs()->SetBoolean(crostini::prefs::kCrostiniEnabled, true);
   install_start_time_ = base::TimeTicks::Now();
 
   // The default value of kCrostiniContainers is set to migrate existing
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
index 4d98d30..27c3d4a 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -708,6 +708,8 @@
   } else if (browser_view()->IsBrowserTypeHostedApp()) {
     active_color = browser_view()->browser()->app_controller()->GetThemeColor();
   } else if (!browser_view()->browser()->is_app()) {
+    // TODO(crbug.com/836128): Remove when System Web Apps flag is removed, as
+    // the above Hosted App branch will render the theme color.
     active_color =
         base::FeatureList::IsEnabled(chromeos::features::kSplitSettings)
             ? gfx::kGoogleGrey050
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_browsertest.cc
index 67b6cc1..976f17e0 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/browser/ui/views/payments/payment_request_browsertest_base.h"
@@ -24,6 +25,11 @@
 #include "ui/views/controls/styled_label.h"
 #include "url/gurl.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/web_applications/system_web_app_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#endif
+
 namespace payments {
 
 using ::testing::UnorderedElementsAre;
@@ -400,6 +406,13 @@
 
 // Tests that clicking the settings link brings the user to settings.
 IN_PROC_BROWSER_TEST_F(PaymentRequestSettingsLinkTest, ClickSettingsLink) {
+#if defined(OS_CHROMEOS)
+  // Install the Settings App.
+  web_app::WebAppProvider::Get(browser()->profile())
+      ->system_web_app_manager()
+      .InstallSystemAppsForTesting();
+#endif
+
   NavigateTo("/payment_request_no_shipping_test.html");
   // Setup a credit card with an associated billing address.
   autofill::AutofillProfile billing_address = autofill::test::GetFullProfile();
diff --git a/chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.cc b/chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.cc
index d871245..637a0d3 100644
--- a/chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.cc
+++ b/chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.cc
@@ -103,7 +103,7 @@
             ->GetExtensionById(GetAppIdFromApplicationName(browser->app_name()),
                                extensions::ExtensionRegistry::EVERYTHING);
 
-    if (browser_extension->id() == extension->id())
+    if (browser_extension && browser_extension->id() == extension->id())
       return browser;
   }
 
diff --git a/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc b/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
index e006b48..6013fe4 100644
--- a/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
@@ -15,7 +15,6 @@
 #include "components/login/localized_values_builder.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
-#include "ui/base/l10n/l10n_util.h"
 
 namespace chromeos {
 namespace network_element {
@@ -264,8 +263,6 @@
       {"networkConfigSaveCredentials",
        IDS_SETTINGS_INTERNET_CONFIG_SAVE_CREDENTIALS},
       {"networkConfigShare", IDS_SETTINGS_INTERNET_CONFIG_SHARE},
-      {"networkAutoConnect", IDS_SETTINGS_INTERNET_NETWORK_AUTO_CONNECT},
-      {"hiddenNetworkWarning", IDS_SETTINGS_HIDDEN_NETWORK_WARNING},
       {"hidePassword", IDS_SETTINGS_PASSWORD_HIDE},
       {"showPassword", IDS_SETTINGS_PASSWORD_SHOW},
   };
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h
index 0844fb6..9309252 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h
@@ -15,6 +15,7 @@
 #include "chrome/browser/printing/cloud_print/cloud_print_printer_list.h"
 #include "chrome/browser/printing/cloud_print/privet_device_lister.h"
 #include "chrome/browser/printing/cloud_print/privet_http.h"
+#include "components/prefs/pref_member.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "printing/buildflags/buildflags.h"
 #include "services/identity/public/cpp/identity_manager.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc
index 8cba903e..829d609a0 100644
--- a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc
@@ -6,10 +6,13 @@
 
 #include <utility>
 
+#include "ash/public/cpp/toast_data.h"
+#include "ash/public/cpp/toast_manager.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
@@ -18,10 +21,12 @@
 #include "chrome/browser/ui/webui/chromeos/account_migration_welcome_dialog.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h"
+#include "chrome/grit/generated_resources.h"
 #include "chromeos/components/account_manager/account_manager_factory.h"
 #include "components/user_manager/user.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/webui/web_ui_util.h"
 #include "ui/chromeos/resources/grit/ui_chromeos_resources.h"
@@ -33,6 +38,9 @@
 namespace {
 
 constexpr char kFamilyLink[] = "Family Link";
+constexpr int kToastDurationMs = 2500;
+constexpr char kAccountRemovedToastId[] =
+    "settings_account_manager_account_removed";
 
 std::string GetEnterpriseDomainFromUsername(const std::string& username) {
   size_t email_separator_pos = username.find('@');
@@ -79,6 +87,11 @@
   }
 }
 
+void ShowToast(const std::string& id, const base::string16& message) {
+  ash::ToastManager::Get()->Show(ash::ToastData(
+      id, message, kToastDurationMs, /*dismiss_text=*/base::nullopt));
+}
+
 }  // namespace
 
 AccountManagerUIHandler::AccountManagerUIHandler(
@@ -258,6 +271,16 @@
   }
 
   account_manager_->RemoveAccount(account_key);
+
+  // Show toast with removal message.
+  const base::Value* email_value = dictionary->FindKey("email");
+  const std::string email = email_value->GetString();
+  DCHECK(!email.empty());
+
+  ShowToast(kAccountRemovedToastId,
+            l10n_util::GetStringFUTF16(
+                IDS_SETTINGS_ACCOUNT_MANAGER_ACCOUNT_REMOVED_MESSAGE,
+                base::UTF8ToUTF16(email)));
 }
 
 void AccountManagerUIHandler::HandleShowWelcomeDialogIfRequired(
diff --git a/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc b/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc
index ece18cf..ee9746e 100644
--- a/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc
@@ -37,7 +37,6 @@
       "removeKerberosAccount",
       base::BindRepeating(&KerberosAccountsHandler::HandleRemoveKerberosAccount,
                           weak_factory_.GetWeakPtr()));
-
   web_ui()->RegisterMessageCallback(
       "setAsActiveKerberosAccount",
       base::BindRepeating(
@@ -77,7 +76,7 @@
 
     base::DictionaryValue account_dict;
     account_dict.SetString("principalName", account.principal_name());
-    account_dict.SetString("krb5conf", account.krb5conf());
+    account_dict.SetString("config", account.krb5conf());
     account_dict.SetBoolean("isSignedIn", account.tgt_validity_seconds() > 0);
     account_dict.SetBoolean("isActive",
                             account.principal_name() == active_principal);
@@ -98,15 +97,17 @@
   //   - Prevent account changes when Kerberos is disabled.
   //   - Remove all accounts when Kerberos is disabled.
 
-  CHECK_EQ(4U, args->GetSize());
+  CHECK_EQ(6U, args->GetSize());
   const std::string& callback_id = args->GetList()[0].GetString();
   const std::string& principal_name = args->GetList()[1].GetString();
   const std::string& password = args->GetList()[2].GetString();
   const bool remember_password = args->GetList()[3].GetBool();
+  const std::string& config = args->GetList()[4].GetString();
+  const bool allow_existing = args->GetList()[5].GetBool();
 
   KerberosCredentialsManager::Get().AddAccountAndAuthenticate(
       std::move(principal_name), false /* is_managed */, password,
-      remember_password, base::nullopt /* krb5_conf */,
+      remember_password, config, allow_existing,
       base::BindOnce(&KerberosAccountsHandler::OnAddAccountAndAuthenticate,
                      weak_factory_.GetWeakPtr(), callback_id));
 }
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
index cfab0568..3c7e072c 100644
--- a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
@@ -114,6 +114,7 @@
   if (web_app::SystemWebAppManager::IsEnabled()) {
     html_source->AddResourcePath("icon-192.png", IDR_SETTINGS_LOGO_192);
     html_source->AddResourcePath("pwa.html", IDR_PWA_HTML);
+    html_source->AddResourcePath("manifest.json", IDR_OS_SETTINGS_MANIFEST);
   }
 
 #if BUILDFLAG(OPTIMIZE_WEBUI)
@@ -123,7 +124,6 @@
   html_source->AddResourcePath("chromeos/lazy_load.html",
                                IDR_OS_SETTINGS_LAZY_LOAD_VULCANIZED_HTML);
   html_source->SetDefaultResource(IDR_OS_SETTINGS_VULCANIZED_HTML);
-  html_source->AddResourcePath("manifest.json", IDR_OS_SETTINGS_MANIFEST);
 #else
   // Add all settings resources.
   for (size_t i = 0; i < kOsSettingsResourcesSize; ++i) {
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 67d8db9..2c898bb 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -68,6 +68,7 @@
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/assistant/assistant_util.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
+#include "chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h"
 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h"
 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
@@ -1741,6 +1742,8 @@
     {"kerberosAccountsListHeader", IDS_SETTINGS_KERBEROS_ACCOUNTS_LIST_HEADER},
     {"kerberosAccountsAddAccountLabel",
      IDS_SETTINGS_KERBEROS_ACCOUNTS_ADD_ACCOUNT_LABEL},
+    {"kerberosAccountsRefreshNowLabel",
+     IDS_SETTINGS_KERBEROS_ACCOUNTS_REFRESH_NOW_LABEL},
     {"kerberosAccountsSetAsActiveAccountLabel",
      IDS_SETTINGS_KERBEROS_ACCOUNTS_SET_AS_ACTIVE_ACCOUNT_LABEL},
     {"kerberosAccountsRemoveAccountLabel",
@@ -1754,12 +1757,20 @@
      IDS_SETTINGS_ADD_KERBEROS_ACCOUNT_REMEMBER_PASSWORD},
     {"kerberosUsername", IDS_SETTINGS_KERBEROS_USERNAME},
     {"kerberosPassword", IDS_SETTINGS_KERBEROS_PASSWORD},
+    {"kerberosConfig", IDS_SETTINGS_KERBEROS_CONFIG},
+    {"kerberosAdvancedConfigLabel",
+     IDS_SETTINGS_KERBEROS_ACCOUNTS_ADVANCED_CONFIG_LABEL},
+    {"kerberosAdvancedConfigTitle",
+     IDS_SETTINGS_KERBEROS_ADVANCED_CONFIG_TITLE},
+    {"kerberosAdvancedConfigDesc", IDS_SETTINGS_KERBEROS_ADVANCED_CONFIG_DESC},
     {"kerberosErrorNetworkProblem",
      IDS_SETTINGS_KERBEROS_ERROR_NETWORK_PROBLEM},
     {"kerberosErrorUsernameInvalid",
      IDS_SETTINGS_KERBEROS_ERROR_USERNAME_INVALID},
     {"kerberosErrorUsernameUnknown",
      IDS_SETTINGS_KERBEROS_ERROR_USERNAME_UNKNOWN},
+    {"kerberosErrorDuplicatePrincipalName",
+     IDS_SETTINGS_KERBEROS_ERROR_DUPLICATE_PRINCIPAL_NAME},
     {"kerberosErrorContactingServer",
      IDS_SETTINGS_KERBEROS_ERROR_CONTACTING_SERVER},
     {"kerberosErrorPasswordInvalid",
@@ -2053,6 +2064,11 @@
   html_source->AddBoolean(
       "isKerberosEnabled",
       g_browser_process->local_state()->GetBoolean(prefs::kKerberosEnabled));
+
+  // Kerberos default configuration.
+  html_source->AddString(
+      "defaultKerberosConfig",
+      chromeos::KerberosCredentialsManager::GetDefaultKerberosConfig());
 #endif
 }
 
diff --git a/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc b/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc
index 864bfb50..b4801fd 100644
--- a/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc
+++ b/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc
@@ -38,9 +38,6 @@
   source->SetJsonPath("strings.js");
   source->AddResourcePath("signin_shared_css.html", IDR_SIGNIN_SHARED_CSS_HTML);
 
-  int title_ids = -1;
-  int confirm_button_ids = -1;
-  int undo_button_ids = -1;
   if (is_sync_allowed) {
     source->SetDefaultResource(IDR_SYNC_CONFIRMATION_HTML);
     source->AddResourcePath("sync_confirmation_browser_proxy.html",
@@ -53,15 +50,19 @@
                             IDR_SYNC_CONFIRMATION_APP_JS);
     source->AddResourcePath("sync_confirmation.js", IDR_SYNC_CONFIRMATION_JS);
 
+    AddStringResource(source, "syncConfirmationTitle",
+                      IDS_SYNC_CONFIRMATION_TITLE);
     AddStringResource(source, "syncConfirmationSyncInfoTitle",
-                      IDS_SYNC_CONFIRMATION_UNITY_SYNC_INFO_TITLE);
+                      IDS_SYNC_CONFIRMATION_SYNC_INFO_TITLE);
     AddStringResource(source, "syncConfirmationSyncInfoDesc",
-                      IDS_SYNC_CONFIRMATION_UNITY_SYNC_INFO_DESC);
+                      IDS_SYNC_CONFIRMATION_SYNC_INFO_DESC);
     AddStringResource(source, "syncConfirmationSettingsInfo",
-                      IDS_SYNC_CONFIRMATION_UNITY_SETTINGS_INFO);
-
+                      IDS_SYNC_CONFIRMATION_SETTINGS_INFO);
     AddStringResource(source, "syncConfirmationSettingsLabel",
-                      IDS_SYNC_CONFIRMATION_DICE_SETTINGS_BUTTON_LABEL);
+                      IDS_SYNC_CONFIRMATION_SETTINGS_BUTTON_LABEL);
+    AddStringResource(source, "syncConfirmationConfirmLabel",
+                      IDS_SYNC_CONFIRMATION_CONFIRM_BUTTON_LABEL);
+    AddStringResource(source, "syncConfirmationUndoLabel", IDS_CANCEL);
 
     constexpr int kAccountPictureSize = 68;
     std::string custom_picture_url = profiles::GetPlaceholderAvatarIconUrl();
@@ -81,31 +82,24 @@
     }
     source->AddString("accountPictureUrl", custom_picture_url);
 
-    title_ids = IDS_SYNC_CONFIRMATION_DICE_TITLE;
-    confirm_button_ids = IDS_SYNC_CONFIRMATION_DICE_CONFIRM_BUTTON_LABEL;
-    undo_button_ids = IDS_CANCEL;
     consent_feature_ = consent_auditor::Feature::CHROME_UNIFIED_CONSENT;
   } else {
     source->SetDefaultResource(IDR_SYNC_DISABLED_CONFIRMATION_HTML);
     source->AddResourcePath("sync_disabled_confirmation.js",
                             IDR_SYNC_DISABLED_CONFIRMATION_JS);
+
+    AddStringResource(source, "syncDisabledConfirmationTitle",
+                      IDS_SYNC_DISABLED_CONFIRMATION_CHROME_SYNC_TITLE);
     AddStringResource(source, "syncDisabledConfirmationDetails",
                       IDS_SYNC_DISABLED_CONFIRMATION_DETAILS);
+    AddStringResource(source, "syncDisabledConfirmationConfirmLabel",
+                      IDS_SYNC_DISABLED_CONFIRMATION_CONFIRM_BUTTON_LABEL);
+    AddStringResource(source, "syncDisabledConfirmationUndoLabel",
+                      IDS_SYNC_DISABLED_CONFIRMATION_UNDO_BUTTON_LABEL);
 
-    title_ids = IDS_SYNC_DISABLED_CONFIRMATION_CHROME_SYNC_TITLE;
-    confirm_button_ids = IDS_SYNC_DISABLED_CONFIRMATION_CONFIRM_BUTTON_LABEL;
-    undo_button_ids = IDS_SYNC_DISABLED_CONFIRMATION_UNDO_BUTTON_LABEL;
     consent_feature_ = consent_auditor::Feature::CHROME_SYNC;
   }
 
-  DCHECK_GE(title_ids, 0);
-  DCHECK_GE(confirm_button_ids, 0);
-  DCHECK_GE(undo_button_ids, 0);
-
-  AddStringResource(source, "syncConfirmationTitle", title_ids);
-  AddStringResource(source, "syncConfirmationConfirmLabel", confirm_button_ids);
-  AddStringResource(source, "syncConfirmationUndoLabel", undo_button_ids);
-
   base::DictionaryValue strings;
   webui::SetLoadTimeDataDefaults(
       g_browser_process->GetApplicationLocale(), &strings);
diff --git a/chrome/browser/web_applications/system_web_app_manager.cc b/chrome/browser/web_applications/system_web_app_manager.cc
index 1b1b863..dad7c61 100644
--- a/chrome/browser/web_applications/system_web_app_manager.cc
+++ b/chrome/browser/web_applications/system_web_app_manager.cc
@@ -22,17 +22,29 @@
 #include "components/version_info/version_info.h"
 #include "content/public/common/content_switches.h"
 
+#if defined(OS_CHROMEOS)
+#include "chromeos/constants/chromeos_features.h"
+#endif  // defined(OS_CHROMEOS)
+
 namespace web_app {
 
 namespace {
 
 base::flat_map<SystemAppType, GURL> CreateSystemWebApps() {
   base::flat_map<SystemAppType, GURL> urls;
+
 // TODO(calamity): Split this into per-platform functions.
 #if defined(OS_CHROMEOS)
-  urls[SystemAppType::DISCOVER] = GURL(chrome::kChromeUIDiscoverURL);
-  constexpr char kChromeSettingsPWAURL[] = "chrome://settings/pwa.html";
-  urls[SystemAppType::SETTINGS] = GURL(kChromeSettingsPWAURL);
+  if (base::FeatureList::IsEnabled(chromeos::features::kDiscoverApp))
+    urls[SystemAppType::DISCOVER] = GURL(chrome::kChromeUIDiscoverURL);
+
+  if (base::FeatureList::IsEnabled(chromeos::features::kSplitSettings)) {
+    constexpr char kChromeSettingsPWAURL[] = "chrome://os-settings/pwa.html";
+    urls[SystemAppType::SETTINGS] = GURL(kChromeSettingsPWAURL);
+  } else {
+    constexpr char kChromeSettingsPWAURL[] = "chrome://settings/pwa.html";
+    urls[SystemAppType::SETTINGS] = GURL(kChromeSettingsPWAURL);
+  }
 #endif  // OS_CHROMEOS
 
   return urls;
diff --git a/chrome/browser/web_applications/system_web_app_manager.h b/chrome/browser/web_applications/system_web_app_manager.h
index 3d25523f..9d87e05 100644
--- a/chrome/browser/web_applications/system_web_app_manager.h
+++ b/chrome/browser/web_applications/system_web_app_manager.h
@@ -57,8 +57,11 @@
   static bool IsEnabled();
 
   // The SystemWebAppManager is disabled in browser tests by default because it
-  // pollutes the startup state. Call this to enable them for SystemWebApp
-  // specific tests.
+  // pollutes the startup state (several tests expect the Extensions state to be
+  // clean).
+  //
+  // Call this to install apps for SystemWebApp specific tests, e.g if a test
+  // needs to open OS Settings.
   void InstallSystemAppsForTesting();
 
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
diff --git a/chrome/chrome_cleaner/engines/broker/scanner_sandbox_interface_unittest.cc b/chrome/chrome_cleaner/engines/broker/scanner_sandbox_interface_unittest.cc
index 04075966..b706537 100644
--- a/chrome/chrome_cleaner/engines/broker/scanner_sandbox_interface_unittest.cc
+++ b/chrome/chrome_cleaner/engines/broker/scanner_sandbox_interface_unittest.cc
@@ -28,6 +28,7 @@
 #include "chrome/chrome_cleaner/os/system_util.h"
 #include "chrome/chrome_cleaner/os/task_scheduler.h"
 #include "chrome/chrome_cleaner/settings/settings.h"
+#include "chrome/chrome_cleaner/test/scoped_process_protector.h"
 #include "chrome/chrome_cleaner/test/test_executables.h"
 #include "chrome/chrome_cleaner/test/test_file_util.h"
 #include "chrome/chrome_cleaner/test/test_native_reg_util.h"
@@ -511,6 +512,24 @@
   test_process.Terminate(/*exit_code=*/1, /*wait=*/false);
 }
 
+TEST(ScannerSandboxInterface, GetProcessCommandLine_AccessDenied) {
+  base::CommandLine test_process_cmd(base::CommandLine::NO_PROGRAM);
+  base::Process test_process =
+      chrome_cleaner::LongRunningProcess(&test_process_cmd);
+  ASSERT_TRUE(test_process.IsValid());
+
+  {
+    // Set up a ScopedProcessProtector that removes only some access rights.
+    chrome_cleaner::ScopedProcessProtector process_protector(
+        test_process.Pid(), PROCESS_QUERY_INFORMATION);
+    base::string16 command_line;
+    EXPECT_FALSE(
+        SandboxGetProcessCommandLine(test_process.Pid(), &command_line));
+  }
+
+  test_process.Terminate(/*exit_code=*/1, /*wait=*/false);
+}
+
 TEST(ScannerSandboxInterface, GetProcessCommandLine_InvalidInput) {
   EXPECT_FALSE(SandboxGetProcessCommandLine(::GetCurrentProcessId(), nullptr));
 
diff --git a/chrome/chrome_cleaner/test/scoped_process_protector.cc b/chrome/chrome_cleaner/test/scoped_process_protector.cc
index ee852db..7252fc6 100644
--- a/chrome/chrome_cleaner/test/scoped_process_protector.cc
+++ b/chrome/chrome_cleaner/test/scoped_process_protector.cc
@@ -6,10 +6,21 @@
 
 #include <aclapi.h>
 
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/strings/string16.h"
+
 namespace chrome_cleaner {
 
 ScopedProcessProtector::ScopedProcessProtector(uint32_t process_id) {
-  Protect(process_id);
+  if (OpenProcess(process_id))
+    DenyAllAccess();
+}
+
+ScopedProcessProtector::ScopedProcessProtector(uint32_t process_id,
+                                               ACCESS_MASK access_to_deny) {
+  if (OpenProcess(process_id))
+    DenyAccess(access_to_deny);
 }
 
 ScopedProcessProtector::~ScopedProcessProtector() {
@@ -32,12 +43,12 @@
   }
 }
 
-void ScopedProcessProtector::Protect(uint32_t process_id) {
+bool ScopedProcessProtector::OpenProcess(uint32_t process_id) {
   // Get an anything-goes handle to the process.
   process_handle_.Set(::OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_id));
   if (!process_handle_.IsValid()) {
     PLOG(ERROR) << "Failed to open process: " << process_id;
-    return;
+    return false;
   }
 
   // Store its existing DACL for cleanup purposes. This API function is weird:
@@ -49,9 +60,13 @@
                       DACL_SECURITY_INFORMATION, NULL, NULL, &original_dacl_,
                       NULL, &original_descriptor_) != ERROR_SUCCESS) {
     PLOG(ERROR) << "Failed to retreieve original DACL.";
-    return;
+    return false;
   }
 
+  return true;
+}
+
+void ScopedProcessProtector::DenyAllAccess() {
   // Set a new empty DACL, effectively denying all things on the process
   // object.
   ACL dacl;
@@ -69,4 +84,37 @@
   initialized_ = true;
 }
 
+void ScopedProcessProtector::DenyAccess(ACCESS_MASK access_to_deny) {
+  // The name of the predefined EVERYONE group.
+  static constexpr base::char16 kEveryoneGroup[] = STRING16_LITERAL("EVERYONE");
+
+  // The Trustee parameter requires a non-const string.
+  base::string16 trustee_name(kEveryoneGroup);
+
+  EXPLICIT_ACCESS access = {};
+  access.grfAccessPermissions = access_to_deny;
+  access.grfAccessMode = DENY_ACCESS;
+  access.grfInheritance = NO_INHERITANCE;
+  access.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
+  access.Trustee.ptstrName = &trustee_name[0];
+
+  // Create a new DACL that merges |access| into the existing DACL.
+  PACL new_dacl = nullptr;
+  if (SetEntriesInAcl(1, &access, original_dacl_, &new_dacl) != ERROR_SUCCESS) {
+    PLOG(ERROR) << "Failed to update DACL.";
+    return;
+  }
+  base::ScopedClosureRunner free_new_dacl(
+      base::BindOnce(base::IgnoreResult(&LocalFree), new_dacl));
+
+  if (SetSecurityInfo(process_handle_.Get(), SE_KERNEL_OBJECT,
+                      DACL_SECURITY_INFORMATION, NULL, NULL, new_dacl,
+                      NULL) != ERROR_SUCCESS) {
+    PLOG(ERROR) << "Failed to set new DACL.";
+    return;
+  }
+
+  initialized_ = true;
+}
+
 }  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/test/scoped_process_protector.h b/chrome/chrome_cleaner/test/scoped_process_protector.h
index 6140e2d..0b6dc96 100644
--- a/chrome/chrome_cleaner/test/scoped_process_protector.h
+++ b/chrome/chrome_cleaner/test/scoped_process_protector.h
@@ -14,12 +14,20 @@
 // Used to prevent a process from being interacted with in any way except via
 // taking ownership and resetting the dacl. Used by tests that want unkillable
 // processes.
+//
 // This protection is defeated by any process that has SeDebugPrivilege (like
 // a debugging process), since that allows the process to get the ALL_ACCESS
 // handle.
 class ScopedProcessProtector {
  public:
+  // Constructs a ScopedProcessProtector that assigns an empty DACL to
+  // |process_id|.
   explicit ScopedProcessProtector(uint32_t process_id);
+
+  // Constructs a ScopedProcessProtector that updates the DACL for
+  // |process_id|, adding DENY_ACCESS for all rights in |access_to_deny|.
+  ScopedProcessProtector(uint32_t process_id, ACCESS_MASK access_to_deny);
+
   ~ScopedProcessProtector();
 
   bool Initialized() { return initialized_; }
@@ -27,7 +35,17 @@
   void Release();
 
  private:
-  void Protect(uint32_t process_id);
+  // Opens |process_id| and gets its current security descriptor. Returns true
+  // on success.
+  bool OpenProcess(uint32_t process_id);
+
+  // Removes all access to the protected process. OpenProcess must be called
+  // first.
+  void DenyAllAccess();
+
+  // Denies the rights in |access_to_deny| to the protected process.
+  // OpenProcess must be called first.
+  void DenyAccess(ACCESS_MASK access_to_deny);
 
   base::win::ScopedHandle process_handle_;
   bool initialized_ = false;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 42bd223..e798aaa3 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -469,7 +469,6 @@
       ":test_support_ui_android",
       "//chrome:chrome_android_core",
       "//chrome/android:app_hooks_java",
-      "//chrome/android:chrome_java",
 
       # TODO(crbug.com/961849): This is needed for ShellManager which is what
       # the ChromeBrowserTestsActivity is using to build the java UI. It's
@@ -513,25 +512,24 @@
 
   android_assets("android_browsertests_assets") {
     testonly = true
+    disable_compression = true
     sources = []
     deps = []
 
     # These are grit() rules so they are in $root_gen_dir.
-    deps += [
-      "//chrome/android:chrome_apk_paks",
-      "//components/resources",
-    ]
-    sources += [
-      "$root_gen_dir/chrome/android/chrome_apk_paks/chrome_100_percent.pak",
-      "$root_gen_dir/chrome/android/chrome_apk_paks/locales/en-US.pak",
-      "$root_gen_dir/chrome/android/chrome_apk_paks/resources.pak",
-      "$root_gen_dir/components/components_resources.pak",
-    ]
+    deps += [ "//components/resources" ]
+    sources += [ "$root_gen_dir/components/components_resources.pak" ]
 
     # These are repack() rules so they are in $root_out_dir.
     deps += [ "//chrome:browser_tests_pak" ]
     sources += [ "$root_out_dir/browser_tests.pak" ]
 
+    # These are assets rules so we can just depend on them.
+    deps += [
+      "//chrome/android:chrome_apk_pak_assets",
+      "//third_party/icu:icu_assets",
+    ]
+
     if (use_v8_context_snapshot) {
       deps += [ "//tools/v8_context_snapshot:v8_context_snapshot_assets" ]
     } else {
@@ -542,10 +540,10 @@
   android_library("android_browsertests_java") {
     testonly = true
     deps = [
-      ":android_browsertests_java_resources",
       "//base:base_java",
       "//base:base_java_test_support",
-      "//chrome/android:chrome_java",
+      "//chrome/android:chrome_all_java",
+      "//content/public/android:content_java",
       "//content/public/test/android:android_test_message_pump_support_java",
       "//content/shell/android:content_shell_browsertests_java",
       "//testing/android/native_test:native_test_java",
@@ -556,12 +554,6 @@
     ]
   }
 
-  android_resources("android_browsertests_java_resources") {
-    testonly = true
-    resource_dirs = [ "//chrome/test/android/browsertests_apk/res" ]
-    custom_package = "org.chromium.android_browsertests_apk"
-  }
-
   jinja_template("android_browsertests_manifest") {
     testonly = true
     input = "//chrome/test/android/browsertests_apk/AndroidManifest.xml.jinja2"
@@ -682,6 +674,7 @@
 
     # Runtime dependencies
     data_deps = [
+      "//chrome/browser/resources/media/mei_preload:component",
       "//ppapi:ppapi_tests",
       "//ppapi:power_saver_test_plugin",
       "//remoting/webapp:browser_test_resources",
@@ -2498,10 +2491,6 @@
       sources += [ "../browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc" ]
     }
 
-    if (!is_mac) {
-      data_deps += [ "//chrome/browser/resources/media/mei_preload:component" ]
-    }
-
     if (toolkit_views && !is_chromeos) {
       sources +=
           [ "../browser/ui/screen_capture_notification_ui_browsertest.cc" ]
diff --git a/chrome/test/android/browsertests_apk/AndroidManifest.xml.jinja2 b/chrome/test/android/browsertests_apk/AndroidManifest.xml.jinja2
index 2da7c15e..1af39f6 100644
--- a/chrome/test/android/browsertests_apk/AndroidManifest.xml.jinja2
+++ b/chrome/test/android/browsertests_apk/AndroidManifest.xml.jinja2
@@ -15,6 +15,7 @@
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
+    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
     <uses-permission android:name="android.permission.RECORD_AUDIO"/>
     <uses-permission android:name="android.permission.VIBRATE"/>
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
diff --git a/chrome/test/android/browsertests_apk/res/layout/test_activity.xml b/chrome/test/android/browsertests_apk/res/layout/test_activity.xml
deleted file mode 100644
index b9b03430..0000000
--- a/chrome/test/android/browsertests_apk/res/layout/test_activity.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!-- Copyright 2019 The Chromium Authors. All rights reserved.
-
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file.
- -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent" android:layout_height="match_parent"
-    android:orientation="vertical">
-    <org.chromium.content_shell.ShellManager
-        android:id="@+id/shell_container"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-</LinearLayout>
diff --git a/chrome/test/android/browsertests_apk/src/org/chromium/android_browsertests_apk/ChromeBrowserTestsActivity.java b/chrome/test/android/browsertests_apk/src/org/chromium/android_browsertests_apk/ChromeBrowserTestsActivity.java
index 7ee2d1a..feb36ee 100644
--- a/chrome/test/android/browsertests_apk/src/org/chromium/android_browsertests_apk/ChromeBrowserTestsActivity.java
+++ b/chrome/test/android/browsertests_apk/src/org/chromium/android_browsertests_apk/ChromeBrowserTestsActivity.java
@@ -5,40 +5,120 @@
 package org.chromium.android_browsertests_apk;
 
 import android.os.Bundle;
+import android.view.Window;
+import android.view.WindowManager;
 
+import org.chromium.base.Log;
+import org.chromium.base.StrictModeContext;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.base.library_loader.LibraryProcessType;
+import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.browser.init.BrowserParts;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.init.EmptyBrowserParts;
-import org.chromium.content_shell.browsertests.ContentShellBrowserTestActivity;
+import org.chromium.content_public.browser.BrowserStartupController;
+import org.chromium.native_test.NativeBrowserTestActivity;
 
 import java.io.File;
 
 /**
  * Android activity for running chrome browser tests.
  */
-public class ChromeBrowserTestsActivity extends ContentShellBrowserTestActivity {
+public class ChromeBrowserTestsActivity extends NativeBrowserTestActivity {
+    private static final String TAG = "cr_browser_test";
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         appendCommandLineFlags(
                 "--remote-debugging-socket-name android_browsertests_devtools_remote");
-
-        // TODO(danakj): This sets up some of the Chrome Java stuff.
-        // AsyncInitializationActivity normally does this for the ChromeActivity.
-        // We skip handlePostNativeStartup() for now, which runs child processes.
-        // We should probably be a SynchronousInitializationActivity, which would
-        // run both of these from onCreate(). But it's not clear yet how we
-        // should be initializing the Chrome UI code (esp ChromeWindow and
-        // CompositorViewHolder) vs using ContentShellBrowserTestActivity and
-        // its ShellManager.
-        BrowserParts parts = new EmptyBrowserParts() {};
-        ChromeBrowserInitializer.getInstance(getApplicationContext()).handlePreNativeStartup(parts);
     }
 
     @Override
     protected void initializeBrowserProcess() {
-        super.initializeBrowserProcess();
+        // TODO(ajwong): This is forked from ContentShellBrowserTestActivity. Should it be pulled
+        // out into a static?
+        try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
+            LibraryLoader.getInstance().ensureInitialized(LibraryProcessType.PROCESS_BROWSER);
+        } catch (ProcessInitException e) {
+            Log.e(TAG, "Cannot load android_browsertests.", e);
+            System.exit(-1);
+        }
+
+        // Don't use the production BrowserStartupController, as we want to replace it with
+        // one that doesn't actually run ContentMain(). The BrowserTestBase class does the
+        // work of ContentMain() itself once we pass control to C++ to run tests. That occurs
+        // after this current method runs.
+        // This replacement startup controller will be used when the C++ code calls into
+        // ChromeBrowserTestsActivity.handlePostNativeStartup() to modify that behaviour.
+        BrowserStartupController startupController = new BrowserStartupController() {
+            @Override
+            public void startBrowserProcessesAsync(boolean startGpuProcess,
+                    boolean startServiceManagerOnly, final StartupCallback callback) {
+                assert false; // Browser tests do a sync startup.
+            }
+
+            @Override
+            public void startBrowserProcessesSync(boolean singleProcess) {
+                ThreadUtils.assertOnUiThread();
+                mStartupCompleted = true;
+                // Runs the stuff that BrowserStartupController wants to do, without actually
+                // running a chrome process.
+                BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
+                        .initChromiumBrowserProcessForTests();
+            }
+
+            @Override
+            public boolean isStartupSuccessfullyCompleted() {
+                ThreadUtils.assertOnUiThread();
+                // Technically C++ code should call through and set this after starting the browser
+                // process but it will have done so by the time it goes through
+                // handlePostNativeStartupSynchronously() which will call
+                // startBrowserProcessesSync() in this class.
+                return mStartupCompleted;
+            }
+
+            @Override
+            public boolean isServiceManagerSuccessfullyStarted() {
+                ThreadUtils.assertOnUiThread();
+                // Technically C++ code should call through and set this after starting the service
+                // manager but it will have done so by the time it goes through
+                // handlePostNativeStartupSynchronously() which will call
+                // startBrowserProcessesSync() in this class.
+                return mStartupCompleted;
+            }
+
+            @Override
+            public void addStartupCompletedObserver(StartupCallback callback) {
+                ThreadUtils.assertOnUiThread();
+                // Pass the callback through to the "real" BrowserStartupController because many
+                // pieces of code will do the same, and we want them all in one place. The
+                // initChromiumBrowserProcessForTests() will run them all so that none are missed.
+                BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
+                        .addStartupCompletedObserver(callback);
+            }
+
+            @Override
+            public void initChromiumBrowserProcessForTests() {
+                assert false;
+            }
+
+            private boolean mStartupCompleted;
+        };
+        ChromeBrowserInitializer.setBrowserStartupControllerForTesting(startupController);
+
+        // This does the pre-native stuff before handing control to C++ with runTests. Then
+        // C++ will call back through handlePostNativeStartupSynchronously() to do the
+        // post-native startup in ChromeBrowserInitializer.
+        final BrowserParts parts = new EmptyBrowserParts() {};
+        ChromeBrowserInitializer.getInstance().handlePreNativeStartup(parts);
+
+        Window wind = this.getWindow();
+        wind.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+        wind.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+        wind.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
     }
 
     @Override
@@ -48,14 +128,4 @@
         return new File(UrlUtils.getIsolatedTestRoot(),
                 ChromeBrowserTestsApplication.PRIVATE_DATA_DIRECTORY_SUFFIX);
     }
-
-    @Override
-    protected int getTestActivityViewId() {
-        return R.layout.test_activity;
-    }
-
-    @Override
-    protected int getShellManagerViewId() {
-        return R.id.shell_container;
-    }
 }
diff --git a/chrome/test/base/android/android_browser_test.cc b/chrome/test/base/android/android_browser_test.cc
index 5f542f1..08882b5 100644
--- a/chrome/test/base/android/android_browser_test.cc
+++ b/chrome/test/base/android/android_browser_test.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/test/base/android/android_browser_test.h"
 
+#include "chrome/browser/android/startup_bridge.h"
 #include "chrome/test/base/test_launcher_utils.h"
 #include "content/public/test/test_utils.h"
 
@@ -26,6 +27,8 @@
 }
 
 void AndroidBrowserTest::PreRunTestOnMainThread() {
+  android_startup::HandlePostNativeStartupSynchronously();
+
   // Pump startup related events.
   content::RunAllPendingInMessageLoop();
 }
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index 0b0aea46..5296fd3 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -71,7 +71,6 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
 #if defined(OS_MACOSX)
-#include "base/mac/foundation_util.h"
 #include "base/mac/scoped_nsautorelease_pool.h"
 #include "chrome/test/base/scoped_bundle_swizzler_mac.h"
 #endif
@@ -168,24 +167,6 @@
 #endif
 
 void InProcessBrowserTest::Initialize() {
-#if defined(OS_MACOSX)
-  base::mac::SetOverrideAmIBundled(true);
-
-  base::FilePath file_exe;
-  CHECK(base::PathService::Get(base::FILE_EXE, &file_exe));
-
-  // Override the path to the running executable to make it look like it is
-  // the browser running as the bundled application.
-  base::FilePath chrome_path =
-      file_exe.DirName().Append(chrome::kBrowserProcessExecutablePath);
-  CHECK(base::PathService::Override(base::FILE_EXE, chrome_path));
-
-  // Then override the path to the child process binaries to point back at
-  // the current test executable, otherwise the FILE_EXE overridden above would
-  // be used to launch children.
-  CHECK(base::PathService::Override(content::CHILD_PROCESS_EXE, file_exe));
-#endif  // defined(OS_MACOSX)
-
   CreateTestServer(GetChromeTestDataDir());
   base::FilePath src_dir;
   CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/ggbflgnkafappblpkiflbgpmkfdpnhhe.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/ggbflgnkafappblpkiflbgpmkfdpnhhe.crx
new file mode 100644
index 0000000..66f96d4
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/webstore/downloads/ggbflgnkafappblpkiflbgpmkfdpnhhe.crx
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/ggbflgnkafappblpkiflbgpmkfdpnhhe.crx.mock-http-headers b/chrome/test/data/chromeos/app_mode/webstore/downloads/ggbflgnkafappblpkiflbgpmkfdpnhhe.crx.mock-http-headers
new file mode 100644
index 0000000..707bb1f
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/webstore/downloads/ggbflgnkafappblpkiflbgpmkfdpnhhe.crx.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OK
+Content-Type: application/x-chrome-extension
diff --git a/chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/ggaeimfdpnmlhdhpcikgoblffmkckdmn b/chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/ggaeimfdpnmlhdhpcikgoblffmkckdmn
index 2e51f295..dfb6d4a7 100644
--- a/chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/ggaeimfdpnmlhdhpcikgoblffmkckdmn
+++ b/chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/ggaeimfdpnmlhdhpcikgoblffmkckdmn
@@ -1,5 +1,5 @@
 {
-  "id": "ahdgpopncncdnljifeaajdjjmdgbkkcm",
+  "id": "ggaeimfdpnmlhdhpcikgoblffmkckdmn",
   "users": "1234",
   "average_rating": 1.0,
   "rating_count": 999,
diff --git a/chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/ggbflgnkafappblpkiflbgpmkfdpnhhe b/chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/ggbflgnkafappblpkiflbgpmkfdpnhhe
new file mode 100644
index 0000000..bd69c66
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/ggbflgnkafappblpkiflbgpmkfdpnhhe
@@ -0,0 +1,11 @@
+{
+  "id": "ggbflgnkafappblpkiflbgpmkfdpnhhe",
+  "users": "1234",
+  "average_rating": 1.0,
+  "rating_count": 999,
+  "verified_site": "chrome.google.com",
+  "localized_name": "Name of App 1",
+  "localized_description": "Description of App 1",
+  "icon_url": "webstore/inlineinstall/detail/app_1_green16x16.png",
+  "manifest":"{ \"manifest_version\": 2, \"name\": \"Test Kiosk App\", \"version\": \"1.0.0\", \"icons\": { \"128\": \"icon-128.png\", \"16\": \"icon-16.png\"}, \"app\": { \"background\": { \"scripts\": [\"main.js\"] } }, \"kiosk_enabled\": true, \"permissions\": [ \"power\", \"webview\" ] }"
+}
diff --git a/chrome/test/data/webui/settings/people_page_kerberos_accounts_test.js b/chrome/test/data/webui/settings/people_page_kerberos_accounts_test.js
index 7a282303..468c7d04 100644
--- a/chrome/test/data/webui/settings/people_page_kerberos_accounts_test.js
+++ b/chrome/test/data/webui/settings/people_page_kerberos_accounts_test.js
@@ -9,6 +9,7 @@
   const testAccounts = [
     {
       principalName: 'user@REALM',
+      config: 'config1',
       isSignedIn: true,
       isActive: true,
       hasRememberedPassword: false,
@@ -16,6 +17,7 @@
     },
     {
       principalName: 'user2@REALM2',
+      config: 'config2',
       isSignedIn: false,
       isActive: false,
       hasRememberedPassword: true,
@@ -44,9 +46,11 @@
     }
 
     /** @override */
-    addAccount(principalName, password, rememberPassword) {
+    addAccount(
+        principalName, password, rememberPassword, config, allowExisting) {
       this.methodCalled(
-          'addAccount', [principalName, password, rememberPassword]);
+          'addAccount',
+          [principalName, password, rememberPassword, config, allowExisting]);
       return Promise.resolve(this.addAccountError);
     }
 
@@ -75,8 +79,9 @@
 
     // Indices of 'More Actions' buttons.
     const MoreActions = {
-      SET_AS_ACTIVE_ACCOUNT: 0,
-      REMOVE_ACCOUNT: 1,
+      REFRESH_NOW: 0,
+      SET_AS_ACTIVE_ACCOUNT: 1,
+      REMOVE_ACCOUNT: 2,
     };
 
     setup(function() {
@@ -133,16 +138,34 @@
         assertTrue(!kerberosAccounts.$$('kerberos-add-account-dialog'));
 
         // Click "Sign-In" on an existing account.
-        // Note that both accounts have a reauth button, but [0] is hidden, so
-        // click [1] (clicking a hidden button works, but it feels weird).
-        kerberosAccounts.root.querySelectorAll('.reauth-button')[1].click();
+        // Note that both accounts have a reauth button, but the first one is
+        // hidden, so click the second one (clicking a hidden button works, but
+        // it feels weird).
+        kerberosAccounts.root.querySelectorAll('.reauth-button')[Account.SECOND]
+            .click();
         Polymer.dom.flush();
 
         // Now the kerberos-add-account-dialog should be open with preset
         // username.
         const addDialog = kerberosAccounts.$$('kerberos-add-account-dialog');
         assertTrue(!!addDialog);
-        assertEquals(testAccounts[1].principalName, addDialog.$.username.value);
+        assertEquals(
+            testAccounts[Account.SECOND].principalName,
+            addDialog.$.username.value);
+      });
+    });
+
+    test('RefreshNow', function() {
+      return browserProxy.whenCalled('getAccounts').then(() => {
+        Polymer.dom.flush();
+        clickMoreActions(Account.FIRST, MoreActions.REFRESH_NOW);
+        Polymer.dom.flush();
+
+        const addDialog = kerberosAccounts.$$('kerberos-add-account-dialog');
+        assertTrue(!!addDialog);
+        assertEquals(
+            testAccounts[Account.FIRST].principalName,
+            addDialog.$.username.value);
       });
     });
 
@@ -181,36 +204,67 @@
   // Tests for the kerberos-add-account-dialog element.
   suite('KerberosAddAccountTests', function() {
     let browserProxy = null;
+
     let dialog = null;
+    let addDialog = null;
+
     let username = null;
     let password = null;
+    let rememberPassword = null;
+    let advancedConfigButton = null;
     let addButton = null;
     let generalError = null;
 
+    // Indices of 'addAccount' params.
+    const AddParams = {
+      PRINCIPAL_NAME: 0,
+      PASSWORD: 1,
+      REMEMBER_PASSWORD: 2,
+      CONFIG: 3,
+      ALLOW_EXISTING: 4,
+    };
+
     setup(function() {
       browserProxy = new TestKerberosAccountsBrowserProxy();
       settings.KerberosAccountsBrowserProxyImpl.instance_ = browserProxy;
       PolymerTest.clearBody();
+      createDialog(null);
+    });
+
+    teardown(function() {
+      dialog.remove();
+    });
+
+    function createDialog(presetAccount) {
+      if (dialog) {
+        dialog.remove();
+      }
 
       dialog = document.createElement('kerberos-add-account-dialog');
+      dialog.presetAccount = presetAccount;
       document.body.appendChild(dialog);
 
+      addDialog = dialog.$.addDialog;
+      assertTrue(!!addDialog);
+
       username = dialog.$.username;
       assertTrue(!!username);
 
       password = dialog.$.password;
       assertTrue(!!password);
 
-      addButton = dialog.$$('.action-button');
+      rememberPassword = dialog.$.rememberPassword;
+      assertTrue(!!rememberPassword);
+
+      advancedConfigButton = dialog.$.advancedConfigButton;
+      assertTrue(!!advancedConfigButton);
+
+      addButton = addDialog.querySelector('.action-button');
       assertTrue(!!addButton);
 
       generalError = dialog.$['general-error-message'];
       assertTrue(!!generalError);
-    });
-
-    teardown(function() {
-      dialog.remove();
-    });
+    }
 
     // Sets |error| as error result for addAccount(), simulates a click on the
     // addAccount button and checks that |errorElement| has an non-empty
@@ -226,54 +280,99 @@
       });
     }
 
-    // The username input field is not disabled by default.
-    test('UsernameFieldNotDisabledByDefault', function() {
+    // Opens the Advanced Config dialog, sets |config| as Kerberos configuration
+    // and clicks 'Save'.
+    function setConfig(config) {
+      advancedConfigButton.click();
+      Polymer.dom.flush();
+      const advancedConfigDialog = dialog.$$('#advancedConfigDialog');
+      advancedConfigDialog.querySelector('#config').value = config;
+      advancedConfigDialog.querySelector('.action-button').click();
+      Polymer.dom.flush();
+    }
+
+    // Opens the Advanced Config dialog, asserts that |config| is set as
+    // Kerberos configuration and clicks 'Cancel'.
+    function assertConfig(config) {
+      advancedConfigButton.click();
+      Polymer.dom.flush();
+      const advancedConfigDialog = dialog.$$('#advancedConfigDialog');
+      assertEquals(config, advancedConfigDialog.querySelector('#config').value);
+      advancedConfigDialog.querySelector('.cancel-button').click();
+      Polymer.dom.flush();
+    }
+
+    // Verifies expected states if no account is preset.
+    test('StatesWithoutPresetAccount', function() {
       assertFalse(username.disabled);
+      assertEquals('', username.value);
+      assertEquals('', password.value);
+      assertConfig(loadTimeData.getString('defaultKerberosConfig'));
+      assertFalse(rememberPassword.checked);
     });
 
-    // The username input field is disabled if a username is preset before the
-    // dialog is appended to the document.
-    test('UsernameFieldDisabledIfPreset', function() {
-      const newDialog = document.createElement('kerberos-add-account-dialog');
-      newDialog.presetAccount = testAccounts[0];
-      document.body.appendChild(newDialog);
-      assertTrue(newDialog.$.username.readonly);
+    // Verifies expected states if an account is preset.
+    test('StatesWithPresetAccount', function() {
+      createDialog(testAccounts[0]);
+      assertTrue(username.readonly);
+      assertEquals(testAccounts[0].principalName, username.value);
+      assertConfig(testAccounts[0].config);
+      // Password and remember password are tested below since the contents
+      // depends on the hasRememberedPassword property of the account.
     });
 
     // The password input field is empty and 'Remember password' is not preset
     // if |hasRememberedPassword| is false.
     test('PasswordNotPresetIfHasRememberedPasswordIsFalse', function() {
-      const newDialog = document.createElement('kerberos-add-account-dialog');
       assertFalse(testAccounts[0].hasRememberedPassword);
-      newDialog.presetAccount = testAccounts[0];
-      document.body.appendChild(newDialog);
-      assertEquals('', newDialog.$.password.value);
-      assertFalse(newDialog.$.rememberPassword.checked);
+      createDialog(testAccounts[0]);
+      assertEquals('', password.value);
+      assertFalse(rememberPassword.checked);
     });
 
     // The password input field is not empty and 'Remember password' is preset
     // if |hasRememberedPassword| is true.
     test('PasswordPresetIfHasRememberedPasswordIsTrue', function() {
-      const newDialog = document.createElement('kerberos-add-account-dialog');
       assertTrue(testAccounts[1].hasRememberedPassword);
-      newDialog.presetAccount = testAccounts[1];
-      document.body.appendChild(newDialog);
-      assertNotEquals('', newDialog.$.password.value);
-      assertTrue(newDialog.$.rememberPassword.checked);
+      createDialog(testAccounts[1]);
+      assertNotEquals('', password.value);
+      assertTrue(rememberPassword.checked);
     });
 
-    // By clicking the "Add account", the username and password values are
-    // passed to the 'addAccount' browser proxy method.
-    test('AddButtonPassesCredentials', function() {
+    // By clicking the "Add account", all field values are passed to the
+    // 'addAccount' browser proxy method.
+    test('AddButtonPassesFieldValues', function() {
       const EXPECTED_USER = 'testuser';
       const EXPECTED_PASS = 'testpass';
+      const EXPECTED_REMEMBER_PASS = true;
+      const EXPECTED_CONFIG = 'testconf';
+
       username.value = EXPECTED_USER;
       password.value = EXPECTED_PASS;
+      setConfig(EXPECTED_CONFIG);
+      rememberPassword.checked = EXPECTED_REMEMBER_PASS;
+
       assertFalse(addButton.disabled);
       addButton.click();
       return browserProxy.whenCalled('addAccount').then(function(args) {
-        assertEquals(EXPECTED_USER, args[0]);
-        assertEquals(EXPECTED_PASS, args[1]);
+        assertEquals(EXPECTED_USER, args[AddParams.PRINCIPAL_NAME]);
+        assertEquals(EXPECTED_PASS, args[AddParams.PASSWORD]);
+        assertEquals(EXPECTED_REMEMBER_PASS, args[AddParams.REMEMBER_PASSWORD]);
+        assertEquals(EXPECTED_CONFIG, args[AddParams.CONFIG]);
+
+        // Should be false if a new account is added. See also
+        // AllowExistingIsTrueForPresetAccounts test.
+        assertFalse(args[AddParams.ALLOW_EXISTING]);
+      });
+    });
+
+    // If an account is preset, overwriting that account should be allowed.
+    test('AllowExistingIsTrueForPresetAccounts', function() {
+      // Populate dialog with preset account.
+      createDialog(testAccounts[1]);
+      addButton.click();
+      return browserProxy.whenCalled('addAccount').then(function(args) {
+        assertTrue(args[AddParams.ALLOW_EXISTING]);
       });
     });
 
@@ -290,33 +389,79 @@
     // If the account has hasRememberedPassword == true and the user just clicks
     // the 'Add' button, an empty password is submitted.
     test('SubmitsEmptyPasswordIfRememberedPasswordIsUsed', function() {
-      const newDialog = document.createElement('kerberos-add-account-dialog');
-      // Note: testAccounts[1].hasRememberedPassword == true.
-      newDialog.presetAccount = testAccounts[1];
-      document.body.appendChild(newDialog);
-      newDialog.$$('.action-button').click();
+      assertTrue(testAccounts[1].hasRememberedPassword);
+      createDialog(testAccounts[1]);
+      addButton.click();
       return browserProxy.whenCalled('addAccount').then(function(args) {
-        assertEquals('', args[1]);  // password
-        assertTrue(args[2]);        // remember password
+        assertEquals('', args[AddParams.PASSWORD]);
+        assertTrue(args[AddParams.REMEMBER_PASSWORD]);
       });
     });
 
     // If the account has hasRememberedPassword == true and the user changes the
     // password before clicking 'Add' button, the changed password is submitted.
     test('SubmitsChangedPasswordIfRememberedPasswordIsChanged', function() {
-      const newDialog = document.createElement('kerberos-add-account-dialog');
-      // Note: testAccounts[1].hasRememberedPassword == true.
-      newDialog.presetAccount = testAccounts[1];
-      document.body.appendChild(newDialog);
-      newDialog.$.password.inputElement.value = 'some edit';
-      newDialog.$.password.dispatchEvent(new CustomEvent('input'));
-      newDialog.$$('.action-button').click();
+      assertTrue(testAccounts[1].hasRememberedPassword);
+      createDialog(testAccounts[1]);
+      password.inputElement.value = 'some edit';
+      password.dispatchEvent(new CustomEvent('input'));
+      addButton.click();
       return browserProxy.whenCalled('addAccount').then(function(args) {
-        assertNotEquals('', args[1]);  // password
-        assertTrue(args[2]);           // remember password
+        assertNotEquals('', args[AddParams.PASSWORD]);
+        assertTrue(args[AddParams.REMEMBER_PASSWORD]);
       });
     });
 
+    test('AdvancedConfigOpenClose', function() {
+      assertTrue(!dialog.$$('#advancedConfigDialog'));
+      assertFalse(addDialog.hidden);
+      advancedConfigButton.click();
+      Polymer.dom.flush();
+
+      let advancedConfigDialog = dialog.$$('#advancedConfigDialog');
+      assertTrue(!!advancedConfigDialog);
+      assertTrue(advancedConfigDialog.open);
+      assertTrue(addDialog.hidden);
+      advancedConfigDialog.querySelector('.action-button').click();
+
+      Polymer.dom.flush();
+      assertTrue(!dialog.$$('#advancedConfigDialog'));
+      assertFalse(addDialog.hidden);
+      assertTrue(addDialog.open);
+    });
+
+    test('AdvancedConfigurationSaveKeepsConfig', function() {
+      advancedConfigButton.click();
+      Polymer.dom.flush();
+      const advancedConfigDialog = dialog.$$('#advancedConfigDialog');
+      assertTrue(!!advancedConfigDialog);
+
+      // Change config and save.
+      const modifiedConfig = 'modified';
+      advancedConfigDialog.querySelector('#config').value = modifiedConfig;
+      advancedConfigDialog.querySelector('.action-button').click();
+
+      // Changed value should stick.
+      Polymer.dom.flush();
+      assertConfig(modifiedConfig);
+    });
+
+    test('AdvancedConfigurationCancelResetsConfig', function() {
+      advancedConfigButton.click();
+      Polymer.dom.flush();
+      const advancedConfigDialog = dialog.$$('#advancedConfigDialog');
+      assertTrue(!!advancedConfigDialog);
+
+      // Change config and cancel.
+      const prevConfig = advancedConfigDialog.querySelector('#config').value;
+      advancedConfigDialog.querySelector('#config').value = 'modified';
+      advancedConfigDialog.querySelector('.cancel-button').click();
+      Polymer.dom.flush();
+
+      // Changed value should NOT stick.
+      assertConfig(prevConfig);
+    });
+
     // addAccount: KerberosErrorType.kNetworkProblem spawns a general error.
     test('AddAccountError_NetworkProblem', function() {
       checkAddAccountError(
@@ -336,6 +481,13 @@
           settings.KerberosErrorType.kBadPrincipal, username.$.error);
     });
 
+    // addAccount: KerberosErrorType.kDuplicatePrincipalName spawns a username
+    // error.
+    test('AddAccountError_DuplicatePrincipalName', function() {
+      checkAddAccountError(
+          settings.KerberosErrorType.kDuplicatePrincipalName, username.$.error);
+    });
+
     // addAccount: KerberosErrorType.kContactingKdcFailed spawns a username
     // error.
     test('AddAccountError_ContactingKdcFailed', function() {
diff --git a/components/autofill/ios/browser/fake_autofill_agent.mm b/components/autofill/ios/browser/fake_autofill_agent.mm
index 3d687042..2f5f8cb5 100644
--- a/components/autofill/ios/browser/fake_autofill_agent.mm
+++ b/components/autofill/ios/browser/fake_autofill_agent.mm
@@ -6,8 +6,8 @@
 
 #include "base/bind.h"
 #include "base/task/post_task.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/components/autofill/ios/browser/fake_js_autofill_manager.mm b/components/autofill/ios/browser/fake_js_autofill_manager.mm
index 8bfb862..daff0e61 100644
--- a/components/autofill/ios/browser/fake_js_autofill_manager.mm
+++ b/components/autofill/ios/browser/fake_js_autofill_manager.mm
@@ -8,8 +8,8 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/task/post_task.h"
 #include "ios/web/public/js_messaging/web_frame.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc b/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
index 24ad2b01..6831878 100644
--- a/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
+++ b/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
@@ -725,23 +725,21 @@
 #endif
     }
 
+#if BUILDFLAG(USE_V4L2_CODEC) && defined(ARCH_CPU_ARM_FAMILY)
+    // TODO(wtlee): Enable DMA-buf test for V4L2 JEA once it supports DMA-buf
+    // encoding.
+#else
     for (size_t i = 0; i < num_concurrent_encoders; i++) {
       encoder_thread.task_runner()->PostTask(
           FROM_HERE,
-          base::BindOnce(&JpegClient::StartEncode,
+          base::BindOnce(&JpegClient::StartEncodeDmaBuf,
                          base::Unretained(clients[i].get()), buffer_id));
     }
 
     for (size_t i = 0; i < num_concurrent_encoders; i++) {
-// For unaligned images, V4L2 may not be able to encode them.
-#if BUILDFLAG(USE_V4L2_CODEC) && defined(ARCH_CPU_ARM_FAMILY)
-      ClientState status = notes[i]->Wait();
-      ASSERT_TRUE(status == ClientState::ENCODE_PASS ||
-                  status == ClientState::ERROR);
-#else
       ASSERT_EQ(notes[i]->Wait(), ClientState::ENCODE_PASS);
-#endif
     }
+#endif
   }
 
   for (size_t i = 0; i < num_concurrent_encoders; i++) {
diff --git a/components/content_capture/common/content_capture_struct_traits_unittest.cc b/components/content_capture/common/content_capture_struct_traits_unittest.cc
index 5bb7b331..f30bf75c 100644
--- a/components/content_capture/common/content_capture_struct_traits_unittest.cc
+++ b/components/content_capture/common/content_capture_struct_traits_unittest.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/message_loop/message_loop.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
 #include "components/content_capture/common/traits_test_service.test-mojom.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -32,7 +32,7 @@
     std::move(callback).Run(i);
   }
 
-  base::MessageLoop loop_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
   mojo::BindingSet<TraitsTestService> traits_test_bindings_;
 
   DISALLOW_COPY_AND_ASSIGN(ContentCaptureStructTraitsTest);
diff --git a/components/crx_file/crx_verifier.cc b/components/crx_file/crx_verifier.cc
index 7aef781..dbc70b4 100644
--- a/components/crx_file/crx_verifier.cc
+++ b/components/crx_file/crx_verifier.cc
@@ -268,6 +268,10 @@
   const uint32_t version =
       ReadAndHashLittleEndianUInt32(&file, file_hash.get());
   VerifierResult result;
+  if (version == 2)
+    LOG(WARNING) << "File '" << crx_path
+                 << "' is in CRX2 format, which is deprecated and will not be "
+                    "supported in M78+";
   if (format == VerifierFormat::CRX2_OR_CRX3 &&
       (version == 2 || (diff && version == 0)))
     result = VerifyCrx2(&file, file_hash.get(), required_key_hashes,
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index 5860082..825b9ba3 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -577,6 +577,8 @@
     int64_t display_id,
     const gfx::Rect& window_bounds,
     int bounds_change) {
+  if (ignore_bounds_change_request_)
+    return;
   // 1) Do no update the bounds unless we have geometry from client.
   // 2) Do not update the bounds if window is minimized unless it
   // exiting the minimzied state.
@@ -976,6 +978,9 @@
 
   bool wasPip = window_state->IsPip();
 
+  // As the bounds of the widget is updated later, ensure that no bounds change
+  // happens with this state change (e.g. updatePipBounds can be triggered).
+  base::AutoReset<bool> resetter(&ignore_bounds_change_request_, true);
   if (client_controlled_state_->EnterNextState(window_state,
                                                pending_window_state_)) {
     client_controlled_state_->set_next_bounds_change_animation_type(
diff --git a/components/exo/client_controlled_shell_surface.h b/components/exo/client_controlled_shell_surface.h
index c30fa22..1002d42 100644
--- a/components/exo/client_controlled_shell_surface.h
+++ b/components/exo/client_controlled_shell_surface.h
@@ -332,6 +332,8 @@
   // TODO(oshima): Remove this once all boards are migrated to P or above.
   bool server_reparent_window_ = false;
 
+  bool ignore_bounds_change_request_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(ClientControlledShellSurface);
 };
 
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
index dc4f4084a..addece11 100644
--- a/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -1973,11 +1973,11 @@
   ui::ScopedAnimationDurationScaleMode animation_scale_mode(
       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
-  EXPECT_EQ(gfx::Rect(8, 8, 256, 256), window->layer()->GetTargetBounds());
-  EXPECT_EQ(gfx::Rect(8, 8, 256, 256), window->layer()->bounds());
+  EXPECT_EQ(gfx::Rect(0, 0, 256, 256), window->layer()->GetTargetBounds());
+  EXPECT_EQ(gfx::Rect(0, 0, 256, 256), window->layer()->bounds());
   window->SetBounds(gfx::Rect(10, 10, 256, 256));
   EXPECT_EQ(gfx::Rect(10, 10, 256, 256), window->layer()->GetTargetBounds());
-  EXPECT_EQ(gfx::Rect(8, 8, 256, 256), window->layer()->bounds());
+  EXPECT_EQ(gfx::Rect(0, 0, 256, 256), window->layer()->bounds());
 }
 
 TEST_F(ClientControlledShellSurfaceTest, PipWindowDragDoesNotAnimate) {
@@ -1995,15 +1995,15 @@
   shell_surface->GetWidget()->Show();
 
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
-  EXPECT_EQ(gfx::Rect(8, 8, 256, 256), window->layer()->GetTargetBounds());
-  EXPECT_EQ(gfx::Rect(8, 8, 256, 256), window->layer()->bounds());
+  EXPECT_EQ(gfx::Rect(0, 0, 256, 256), window->layer()->GetTargetBounds());
+  EXPECT_EQ(gfx::Rect(0, 0, 256, 256), window->layer()->bounds());
   ui::ScopedAnimationDurationScaleMode animation_scale_mode(
       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
   std::unique_ptr<ash::WindowResizer> resizer(ash::CreateWindowResizer(
       window, gfx::Point(), HTCAPTION, ::wm::WINDOW_MOVE_SOURCE_MOUSE));
   resizer->Drag(gfx::Point(10, 10), 0);
-  EXPECT_EQ(gfx::Rect(18, 18, 256, 256), window->layer()->GetTargetBounds());
-  EXPECT_EQ(gfx::Rect(18, 18, 256, 256), window->layer()->bounds());
+  EXPECT_EQ(gfx::Rect(10, 10, 256, 256), window->layer()->GetTargetBounds());
+  EXPECT_EQ(gfx::Rect(10, 10, 256, 256), window->layer()->bounds());
   resizer->CompleteDrag();
 }
 
@@ -2098,4 +2098,32 @@
   surface->Commit();
 }
 
+TEST_F(ClientControlledShellSurfaceDisplayTest,
+       DoNotRequestBoundsChangeWithStateTransition) {
+  gfx::Size buffer_size(64, 64);
+  auto buffer = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+  auto surface = std::make_unique<Surface>();
+  auto shell_surface =
+      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  auto* widget = shell_surface->GetWidget();
+  const gfx::Rect original_bounds(gfx::Point(20, 20), buffer_size);
+  shell_surface->SetGeometry(original_bounds);
+  widget->Restore();
+  surface->Commit();
+
+  shell_surface->set_bounds_changed_callback(base::BindRepeating(
+      &ClientControlledShellSurfaceDisplayTest::OnBoundsChangeEvent,
+      base::Unretained(this), base::Unretained(shell_surface.get())));
+
+  shell_surface->SetPip();
+  surface->Commit();
+
+  ASSERT_EQ(0, bounds_change_count());
+}
+
 }  // namespace exo
diff --git a/components/favicon/ios/favicon_url_util.cc b/components/favicon/ios/favicon_url_util.cc
index 96b624f..a0eb5e1dc 100644
--- a/components/favicon/ios/favicon_url_util.cc
+++ b/components/favicon/ios/favicon_url_util.cc
@@ -9,7 +9,7 @@
 
 #include "components/favicon/core/favicon_url.h"
 #include "components/favicon_base/favicon_types.h"
-#include "ios/web/public/favicon_url.h"
+#include "ios/web/public/favicon/favicon_url.h"
 
 namespace favicon {
 namespace {
diff --git a/components/favicon/ios/web_favicon_driver.mm b/components/favicon/ios/web_favicon_driver.mm
index d8795e3..44e08bc 100644
--- a/components/favicon/ios/web_favicon_driver.mm
+++ b/components/favicon/ios/web_favicon_driver.mm
@@ -9,7 +9,7 @@
 #include "components/favicon/core/favicon_url.h"
 #include "components/favicon/ios/favicon_url_util.h"
 #include "ios/web/public/browser_state.h"
-#include "ios/web/public/favicon_status.h"
+#include "ios/web/public/favicon/favicon_status.h"
 #include "ios/web/public/navigation_item.h"
 #include "ios/web/public/navigation_manager.h"
 #include "ios/web/public/web_state/navigation_context.h"
diff --git a/components/image_fetcher/ios/ios_image_decoder_impl.mm b/components/image_fetcher/ios/ios_image_decoder_impl.mm
index 1f3fe63..aca5ea3 100644
--- a/components/image_fetcher/ios/ios_image_decoder_impl.mm
+++ b/components/image_fetcher/ios/ios_image_decoder_impl.mm
@@ -14,7 +14,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/task/post_task.h"
 #import "components/image_fetcher/ios/webp_decoder.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/image/image.h"
 
diff --git a/components/password_manager/content/browser/content_password_manager_driver.cc b/components/password_manager/content/browser/content_password_manager_driver.cc
index 4d72dd4..1c18433 100644
--- a/components/password_manager/content/browser/content_password_manager_driver.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver.cc
@@ -206,7 +206,7 @@
       !navigation_handle->IsSameDocument()) {
     NotifyDidNavigateMainFrame(navigation_handle->IsRendererInitiated(),
                                navigation_handle->GetPageTransition(),
-                               navigation_handle->HasUserGesture(),
+                               navigation_handle->WasInitiatedByLinkClick(),
                                GetPasswordManager());
     GetPasswordAutofillManager()->DidNavigateMainFrame();
   }
diff --git a/components/password_manager/content/browser/form_submission_tracker_util.cc b/components/password_manager/content/browser/form_submission_tracker_util.cc
index 0e4c3e5..1b46311 100644
--- a/components/password_manager/content/browser/form_submission_tracker_util.cc
+++ b/components/password_manager/content/browser/form_submission_tracker_util.cc
@@ -11,23 +11,21 @@
 
 void NotifyDidNavigateMainFrame(bool is_renderer_initiated,
                                 ui::PageTransition transition,
-                                bool has_user_gesture,
+                                bool was_initiated_by_link_click,
                                 FormSubmissionObserver* observer) {
   DCHECK(observer);
 
   // Password manager is interested in
   // - form submission navigations,
-  // - any JavaScript initiated navigations (i.e. renderer initiated navigations
-  // without user gesture), because many form submissions are done with
-  // JavaScript.
-  // Password manager is not interested in
+  // - any JavaScript initiated navigations, because many form submissions are
+  // done with JavaScript. Password manager is not interested in
   // - browser initiated navigations (e.g. reload, bookmark click),
-  // - hyperlink navigations (which are renderer navigations with user gesture).
+  // - hyperlink navigations.
   bool form_may_be_submitted =
       is_renderer_initiated &&
       (ui::PageTransitionCoreTypeIs(transition,
                                     ui::PAGE_TRANSITION_FORM_SUBMIT) ||
-       !has_user_gesture);
+       !was_initiated_by_link_click);
 
   observer->DidNavigateMainFrame(form_may_be_submitted);
 }
diff --git a/components/password_manager/content/browser/form_submission_tracker_util.h b/components/password_manager/content/browser/form_submission_tracker_util.h
index f91101a..9fde79bd 100644
--- a/components/password_manager/content/browser/form_submission_tracker_util.h
+++ b/components/password_manager/content/browser/form_submission_tracker_util.h
@@ -15,7 +15,7 @@
 // form submision.
 void NotifyDidNavigateMainFrame(bool is_renderer_initiated,
                                 ui::PageTransition transition,
-                                bool has_user_gesture,
+                                bool was_initiated_by_link_click,
                                 FormSubmissionObserver* observer);
 
 }  // namespace password_manager
diff --git a/components/password_manager/content/browser/form_submission_tracker_util_unittest.cc b/components/password_manager/content/browser/form_submission_tracker_util_unittest.cc
index 76685fdf..c6bd5d5 100644
--- a/components/password_manager/content/browser/form_submission_tracker_util_unittest.cc
+++ b/components/password_manager/content/browser/form_submission_tracker_util_unittest.cc
@@ -35,33 +35,33 @@
 TEST_F(FormSubmissionTrackerUtilTest, NotRendererInitiated) {
   EXPECT_CALL(observer(),
               DidNavigateMainFrame(false /* form_may_be_submitted */));
-  NotifyDidNavigateMainFrame(false /* is_renderer_initiated */,
-                             ui::PAGE_TRANSITION_RELOAD,
-                             true /* has_user_gesture */, &observer());
+  NotifyDidNavigateMainFrame(
+      false /* is_renderer_initiated */, ui::PAGE_TRANSITION_RELOAD,
+      true /* was_initiated_by_link_click */, &observer());
 }
 
 TEST_F(FormSubmissionTrackerUtilTest, LinkTransition) {
   EXPECT_CALL(observer(),
               DidNavigateMainFrame(false /* form_may_be_submitted */));
-  NotifyDidNavigateMainFrame(true /* is_renderer_initiated */,
-                             ui::PAGE_TRANSITION_LINK,
-                             true /* has_user_gesture */, &observer());
+  NotifyDidNavigateMainFrame(
+      true /* is_renderer_initiated */, ui::PAGE_TRANSITION_LINK,
+      true /* was_initiated_by_link_click */, &observer());
 }
 
 TEST_F(FormSubmissionTrackerUtilTest, FormSubmission) {
   EXPECT_CALL(observer(),
               DidNavigateMainFrame(true /* form_may_be_submitted */));
-  NotifyDidNavigateMainFrame(true /* is_renderer_initiated */,
-                             ui::PAGE_TRANSITION_FORM_SUBMIT,
-                             true /* has_user_gesture */, &observer());
+  NotifyDidNavigateMainFrame(
+      true /* is_renderer_initiated */, ui::PAGE_TRANSITION_FORM_SUBMIT,
+      true /* was_initiated_by_link_click */, &observer());
 }
 
 TEST_F(FormSubmissionTrackerUtilTest, PageRedirectAfterJavaScriptSubmission) {
   EXPECT_CALL(observer(),
               DidNavigateMainFrame(true /* form_may_be_submitted */));
-  NotifyDidNavigateMainFrame(true /* is_renderer_initiated */,
-                             ui::PAGE_TRANSITION_CLIENT_REDIRECT,
-                             false /* has_user_gesture */, &observer());
+  NotifyDidNavigateMainFrame(
+      true /* is_renderer_initiated */, ui::PAGE_TRANSITION_CLIENT_REDIRECT,
+      false /* was_initiated_by_link_click */, &observer());
 }
 
 }  // namespace
diff --git a/components/proxy_config/ios/proxy_service_factory.cc b/components/proxy_config/ios/proxy_service_factory.cc
index ac86e82..c5fc61d1 100644
--- a/components/proxy_config/ios/proxy_service_factory.cc
+++ b/components/proxy_config/ios/proxy_service_factory.cc
@@ -10,8 +10,8 @@
 
 #include "base/task/post_task.h"
 #include "components/proxy_config/pref_proxy_config_tracker_impl.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/proxy_resolution/proxy_config_service.h"
 #include "net/proxy_resolution/proxy_resolution_service.h"
 
diff --git a/components/search_engines/BUILD.gn b/components/search_engines/BUILD.gn
index 0fc603c1..f0e10cf 100644
--- a/components/search_engines/BUILD.gn
+++ b/components/search_engines/BUILD.gn
@@ -80,6 +80,17 @@
     "//url",
   ]
 
+  if (is_android) {
+    sources += [
+      "android/template_url_android.cc",
+      "android/template_url_android.h",
+      "android/template_url_service_android.cc",
+      "android/template_url_service_android.h",
+    ]
+
+    deps += [ "//components/search_engines/android:jni_headers" ]
+  }
+
   if (!is_ios) {
     sources += [
       "default_search_policy_handler.cc",
diff --git a/components/search_engines/android/BUILD.gn b/components/search_engines/android/BUILD.gn
new file mode 100644
index 0000000..474d8149
--- /dev/null
+++ b/components/search_engines/android/BUILD.gn
@@ -0,0 +1,25 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+
+android_library("java") {
+  deps = [
+    "//base:base_java",
+    "//content/public/android:content_java",
+  ]
+
+  java_files = [
+    "java/src/org/chromium/components/search_engines/TemplateUrl.java",
+    "java/src/org/chromium/components/search_engines/TemplateUrlService.java",
+  ]
+}
+
+generate_jni("jni_headers") {
+  sources = [
+    "java/src/org/chromium/components/search_engines/TemplateUrl.java",
+    "java/src/org/chromium/components/search_engines/TemplateUrlService.java",
+  ]
+  jni_package = "search_engines"
+}
diff --git a/components/search_engines/android/DEPS b/components/search_engines/android/DEPS
new file mode 100644
index 0000000..38f4bbd
--- /dev/null
+++ b/components/search_engines/android/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+  "+components/search_provider_logos",
+  # Remove content dependencies: https://crbug.com/968156
+  "-content/public/android/java",
+  "+content/public/android/java/src/org/chromium/content_public",
+  "+jni"
+]
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrl.java b/components/search_engines/android/java/src/org/chromium/components/search_engines/TemplateUrl.java
similarity index 97%
rename from chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrl.java
rename to components/search_engines/android/java/src/org/chromium/components/search_engines/TemplateUrl.java
index f3bd8673..962bd46 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrl.java
+++ b/components/search_engines/android/java/src/org/chromium/components/search_engines/TemplateUrl.java
@@ -1,7 +1,7 @@
 // Copyright 2018 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-package org.chromium.chrome.browser.search_engines;
+package org.chromium.components.search_engines;
 
 import org.chromium.base.annotations.CalledByNative;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java b/components/search_engines/android/java/src/org/chromium/components/search_engines/TemplateUrlService.java
similarity index 80%
rename from chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java
rename to components/search_engines/android/java/src/org/chromium/components/search_engines/TemplateUrlService.java
index 55c72cd..04bfbf2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java
+++ b/components/search_engines/android/java/src/org/chromium/components/search_engines/TemplateUrlService.java
@@ -2,7 +2,7 @@
 // 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.search_engines;
+package org.chromium.components.search_engines;
 
 import android.support.annotation.Nullable;
 
@@ -26,13 +26,10 @@
  * See components/search_engines/template_url_service.h for more details.
  */
 public class TemplateUrlService {
-
     /**
      * This listener will be notified when template url service is done loading.
      */
-    public interface LoadListener {
-        void onTemplateUrlServiceLoaded();
-    }
+    public interface LoadListener { void onTemplateUrlServiceLoaded(); }
 
     /**
      * Observer to be notified whenever the set of TemplateURLs are modified.
@@ -44,25 +41,24 @@
         void onTemplateURLServiceChanged();
     }
 
-    private static TemplateUrlService sService;
+    private final ObserverList<LoadListener> mLoadListeners = new ObserverList<>();
+    private final ObserverList<TemplateUrlServiceObserver> mObservers = new ObserverList<>();
+    private long mNativeTemplateUrlServiceAndroid;
 
-    public static TemplateUrlService getInstance() {
-        ThreadUtils.assertOnUiThread();
-        if (sService == null) {
-            sService = new TemplateUrlService();
-        }
-        return sService;
+    private TemplateUrlService(long nativeTemplateUrlServiceAndroid) {
+        // Note that this technically leaks the native object, however, TemplateUrlService
+        // is a singleton that lives forever and there's no clean shutdown of Chrome on Android.
+        mNativeTemplateUrlServiceAndroid = nativeTemplateUrlServiceAndroid;
     }
 
-    private final long mNativeTemplateUrlServiceAndroid;
-    private final ObserverList<LoadListener> mLoadListeners = new ObserverList<LoadListener>();
-    private final ObserverList<TemplateUrlServiceObserver> mObservers =
-            new ObserverList<TemplateUrlServiceObserver>();
+    @CalledByNative
+    private static TemplateUrlService create(long nativeTemplateUrlServiceAndroid) {
+        return new TemplateUrlService(nativeTemplateUrlServiceAndroid);
+    }
 
-    private TemplateUrlService() {
-        // Note that this technically leaks the native object, however, TemlateUrlService
-        // is a singleton that lives forever and there's no clean shutdown of Chrome on Android
-        mNativeTemplateUrlServiceAndroid = nativeInit();
+    @CalledByNative
+    private void clearNativePtr() {
+        mNativeTemplateUrlServiceAndroid = 0;
     }
 
     public boolean isLoaded() {
@@ -177,10 +173,6 @@
         return nativeIsDefaultSearchEngineGoogle(mNativeTemplateUrlServiceAndroid);
     }
 
-    public boolean doesDefaultSearchEngineHaveLogo() {
-        return nativeDoesDefaultSearchEngineHaveLogo(mNativeTemplateUrlServiceAndroid);
-    }
-
     /**
      * Checks whether a search result page is from a default search provider.
      * @param url The url for the search result page.
@@ -204,13 +196,10 @@
         // If the load has already been completed, post a load complete to the observer.  Done
         // as an asynchronous call to keep the client code predictable in the loaded/unloaded state.
         if (isLoaded()) {
-            PostTask.postTask(UiThreadTaskTraits.DEFAULT, new Runnable() {
-                @Override
-                public void run() {
-                    if (!mLoadListeners.hasObserver(listener)) return;
+            PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> {
+                if (!mLoadListeners.hasObserver(listener)) return;
 
-                    listener.onTemplateUrlServiceLoaded();
-                }
+                listener.onTemplateUrlServiceLoaded();
             });
         }
     }
@@ -266,18 +255,6 @@
     }
 
     /**
-     * Replaces the search terms from {@code query} in {@code url}.
-     * @param query The {@link String} that represents the text query that should replace the
-     *              existing query in {@code url}.
-     * @param url   The {@link String} that contains the search url with another search query that
-     *              will be replaced with {@code query}.
-     * @return      A new version of {@code url} with the search term replaced with {@code query}.
-     */
-    public String replaceSearchTermsInUrl(String query, String url) {
-        return nativeReplaceSearchTermsInUrl(mNativeTemplateUrlServiceAndroid, query, url);
-    }
-
-    /**
      * Finds the default search engine for the default provider and returns the url query
      * {@link String} for {@code query} with the contextual search version param set.
      * @param query The search term to use as the main query in the returned search url.
@@ -312,15 +289,6 @@
         return nativeGetSearchEngineTypeFromTemplateUrl(mNativeTemplateUrlServiceAndroid, keyword);
     }
 
-    /**
-     * Extracts the search query terms from a SRP URL.
-     * @param url The SRP URL.
-     * @return A string containing just the search terms stripped from the SRP URL.
-     */
-    public String extractSearchTermsFromUrl(String url) {
-        return nativeExtractSearchTermsFromUrl(mNativeTemplateUrlServiceAndroid, url);
-    }
-
     @VisibleForTesting
     public String addSearchEngineForTesting(String keyword, int ageInDays) {
         return nativeAddSearchEngineForTesting(
@@ -332,12 +300,6 @@
         return nativeUpdateLastVisitedForTesting(mNativeTemplateUrlServiceAndroid, keyword);
     }
 
-    @VisibleForTesting
-    static void setInstanceForTesting(TemplateUrlService service) {
-        sService = service;
-    }
-
-    private native long nativeInit();
     private native void nativeLoad(long nativeTemplateUrlServiceAndroid);
     private native boolean nativeIsLoaded(long nativeTemplateUrlServiceAndroid);
     private native void nativeSetUserSelectedDefaultSearchProvider(
@@ -347,14 +309,10 @@
             long nativeTemplateUrlServiceAndroid, String url);
     private native boolean nativeIsSearchByImageAvailable(long nativeTemplateUrlServiceAndroid);
     private native boolean nativeIsDefaultSearchEngineGoogle(long nativeTemplateUrlServiceAndroid);
-    private native boolean nativeDoesDefaultSearchEngineHaveLogo(
-            long nativeTemplateUrlServiceAndroid);
-    private native String nativeGetUrlForSearchQuery(long nativeTemplateUrlServiceAndroid,
-            String query);
-    private native String nativeGetUrlForVoiceSearchQuery(long nativeTemplateUrlServiceAndroid,
-            String query);
-    private native String nativeReplaceSearchTermsInUrl(long nativeTemplateUrlServiceAndroid,
-            String query, String currentUrl);
+    private native String nativeGetUrlForSearchQuery(
+            long nativeTemplateUrlServiceAndroid, String query);
+    private native String nativeGetUrlForVoiceSearchQuery(
+            long nativeTemplateUrlServiceAndroid, String query);
     private native String nativeGetUrlForContextualSearchQuery(long nativeTemplateUrlServiceAndroid,
             String query, String alternateTerm, boolean shouldPrefetch, String protocolVersion);
     private native String nativeGetSearchEngineUrlFromTemplateUrl(
@@ -365,8 +323,6 @@
             long nativeTemplateUrlServiceAndroid, String keyword, int offset);
     private native String nativeUpdateLastVisitedForTesting(
             long nativeTemplateUrlServiceAndroid, String keyword);
-    private native String nativeExtractSearchTermsFromUrl(
-            long nativeTemplateUrlServiceAndroid, String url);
     private native void nativeGetTemplateUrls(
             long nativeTemplateUrlServiceAndroid, List<TemplateUrl> templateUrls);
     private native TemplateUrl nativeGetDefaultSearchEngine(long nativeTemplateUrlServiceAndroid);
diff --git a/chrome/browser/search_engines/template_url_android.cc b/components/search_engines/android/template_url_android.cc
similarity index 77%
rename from chrome/browser/search_engines/template_url_android.cc
rename to components/search_engines/android/template_url_android.cc
index dfed298..dc04300 100644
--- a/chrome/browser/search_engines/template_url_android.cc
+++ b/components/search_engines/android/template_url_android.cc
@@ -1,8 +1,8 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/search_engines/template_url_android.h"
+#include "components/search_engines/android/template_url_android.h"
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
@@ -25,9 +25,8 @@
                                                  template_url->short_name());
 }
 
-ScopedJavaLocalRef<jstring> JNI_TemplateUrl_GetKeyword(
-    JNIEnv* env,
-    jlong template_url_ptr) {
+ScopedJavaLocalRef<jstring> JNI_TemplateUrl_GetKeyword(JNIEnv* env,
+                                                       jlong template_url_ptr) {
   TemplateURL* template_url = ToTemplateURL(template_url_ptr);
   return base::android::ConvertUTF16ToJavaString(env, template_url->keyword());
 }
@@ -40,14 +39,12 @@
          template_url->created_by_policy();
 }
 
-jlong JNI_TemplateUrl_GetLastVisitedTime(JNIEnv* env,
-                                         jlong template_url_ptr) {
+jlong JNI_TemplateUrl_GetLastVisitedTime(JNIEnv* env, jlong template_url_ptr) {
   TemplateURL* template_url = ToTemplateURL(template_url_ptr);
   return template_url->last_visited().ToJavaTime();
 }
 
-jint JNI_TemplateUrl_GetPrepopulatedId(JNIEnv* env,
-                                       jlong template_url_ptr) {
+jint JNI_TemplateUrl_GetPrepopulatedId(JNIEnv* env, jlong template_url_ptr) {
   TemplateURL* template_url = ToTemplateURL(template_url_ptr);
   return template_url->prepopulate_id();
 }
diff --git a/components/search_engines/android/template_url_android.h b/components/search_engines/android/template_url_android.h
new file mode 100644
index 0000000..b0a16bdc
--- /dev/null
+++ b/components/search_engines/android/template_url_android.h
@@ -0,0 +1,16 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SEARCH_ENGINES_ANDROID_TEMPLATE_URL_ANDROID_H_
+#define COMPONENTS_SEARCH_ENGINES_ANDROID_TEMPLATE_URL_ANDROID_H_
+
+#include "base/android/jni_weak_ref.h"
+#include "base/android/scoped_java_ref.h"
+#include "components/search_engines/template_url.h"
+
+base::android::ScopedJavaLocalRef<jobject> CreateTemplateUrlAndroid(
+    JNIEnv* env,
+    const TemplateURL* template_url);
+
+#endif  // COMPONENTS_SEARCH_ENGINES_ANDROID_TEMPLATE_URL_ANDROID_H_
diff --git a/chrome/browser/search_engines/template_url_service_android.cc b/components/search_engines/android/template_url_service_android.cc
similarity index 67%
rename from chrome/browser/search_engines/template_url_service_android.cc
rename to components/search_engines/android/template_url_service_android.cc
index df23c7b..da85964 100644
--- a/chrome/browser/search_engines/template_url_service_android.cc
+++ b/components/search_engines/android/template_url_service_android.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/browser/search_engines/template_url_service_android.h"
+#include "components/search_engines/android/template_url_service_android.h"
 
 #include <stddef.h>
 
@@ -14,47 +14,46 @@
 #include "base/format_macros.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/search_engines/template_url_android.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "components/google/core/common/google_util.h"
+#include "components/search_engines/android/template_url_android.h"
 #include "components/search_engines/search_terms_data.h"
 #include "components/search_engines/template_url.h"
 #include "components/search_engines/template_url_prepopulate_data.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/search_engines/util.h"
-#include "components/search_provider_logos/features.h"
-#include "components/search_provider_logos/switches.h"
 #include "jni/TemplateUrlService_jni.h"
 #include "net/base/url_util.h"
 
 using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
-namespace {
-
-Profile* GetOriginalProfile() {
-  return ProfileManager::GetActiveUserProfile()->GetOriginalProfile();
-}
-
-}  // namespace
-
-TemplateUrlServiceAndroid::TemplateUrlServiceAndroid(JNIEnv* env,
-                                                     jobject obj)
-    : weak_java_obj_(env, obj),
-      template_url_service_(
-          TemplateURLServiceFactory::GetForProfile(GetOriginalProfile())) {
-  template_url_subscription_ =
-      template_url_service_->RegisterOnLoadedCallback(
-          base::Bind(&TemplateUrlServiceAndroid::OnTemplateURLServiceLoaded,
-                     base::Unretained(this)));
+TemplateUrlServiceAndroid::TemplateUrlServiceAndroid(
+    TemplateURLService* template_url_service)
+    : template_url_service_(template_url_service) {
+  template_url_subscription_ = template_url_service_->RegisterOnLoadedCallback(
+      base::Bind(&TemplateUrlServiceAndroid::OnTemplateURLServiceLoaded,
+                 base::Unretained(this)));
   template_url_service_->AddObserver(this);
 }
 
 TemplateUrlServiceAndroid::~TemplateUrlServiceAndroid() {
+  if (java_ref_) {
+    Java_TemplateUrlService_clearNativePtr(base::android::AttachCurrentThread(),
+                                           java_ref_);
+    java_ref_.Reset();
+  }
   template_url_service_->RemoveObserver(this);
 }
 
+ScopedJavaLocalRef<jobject> TemplateUrlServiceAndroid::GetJavaObject() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  if (!java_ref_) {
+    java_ref_.Reset(
+        Java_TemplateUrlService_create(env, reinterpret_cast<intptr_t>(this)));
+  }
+  return ScopedJavaLocalRef<jobject>(java_ref_);
+}
+
 void TemplateUrlServiceAndroid::Load(JNIEnv* env,
                                      const JavaParamRef<jobject>& obj) {
   template_url_service_->Load();
@@ -89,9 +88,9 @@
   const TemplateURL* default_search_provider =
       template_url_service_->GetDefaultSearchProvider();
   return default_search_provider &&
-      !default_search_provider->image_url().empty() &&
-      default_search_provider->image_url_ref().IsValid(
-          template_url_service_->search_terms_data());
+         !default_search_provider->image_url().empty() &&
+         default_search_provider->image_url_ref().IsValid(
+             template_url_service_->search_terms_data());
 }
 
 jboolean TemplateUrlServiceAndroid::IsDefaultSearchEngineGoogle(
@@ -100,35 +99,8 @@
   const TemplateURL* default_search_provider =
       template_url_service_->GetDefaultSearchProvider();
   return default_search_provider &&
-      default_search_provider->url_ref().HasGoogleBaseURLs(
-          template_url_service_->search_terms_data());
-}
-
-jboolean TemplateUrlServiceAndroid::DoesDefaultSearchEngineHaveLogo(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  // |kSearchProviderLogoURL| applies to all search engines (Google or
-  // third-party).
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          search_provider_logos::switches::kSearchProviderLogoURL)) {
-    return true;
-  }
-
-  // Google always has a logo.
-  if (IsDefaultSearchEngineGoogle(env, obj))
-    return true;
-
-  // Third-party search engines can have a doodle specified via the command
-  // line, or a static logo or doodle from the TemplateURLService.
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          search_provider_logos::switches::kThirdPartyDoodleURL)) {
-    return true;
-  }
-  const TemplateURL* default_search_provider =
-      template_url_service_->GetDefaultSearchProvider();
-  return default_search_provider &&
-         (default_search_provider->doodle_url().is_valid() ||
-          default_search_provider->logo_url().is_valid());
+         default_search_provider->url_ref().HasGoogleBaseURLs(
+             template_url_service_->search_terms_data());
 }
 
 jboolean
@@ -144,20 +116,16 @@
 void TemplateUrlServiceAndroid::OnTemplateURLServiceLoaded() {
   template_url_subscription_.reset();
   JNIEnv* env = base::android::AttachCurrentThread();
-  auto java_obj = weak_java_obj_.get(env);
-  if (java_obj.is_null())
+  if (!java_ref_)
     return;
-
-  Java_TemplateUrlService_templateUrlServiceLoaded(env, java_obj);
+  Java_TemplateUrlService_templateUrlServiceLoaded(env, java_ref_);
 }
 
 void TemplateUrlServiceAndroid::OnTemplateURLServiceChanged() {
   JNIEnv* env = base::android::AttachCurrentThread();
-  auto java_obj = weak_java_obj_.get(env);
-  if (java_obj.is_null())
+  if (!java_ref_)
     return;
-
-  Java_TemplateUrlService_onTemplateURLServiceChanged(env, java_obj);
+  Java_TemplateUrlService_onTemplateURLServiceChanged(env, java_ref_);
 }
 
 base::android::ScopedJavaLocalRef<jstring>
@@ -202,29 +170,6 @@
 }
 
 base::android::ScopedJavaLocalRef<jstring>
-TemplateUrlServiceAndroid::ReplaceSearchTermsInUrl(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jstring>& jquery,
-    const JavaParamRef<jstring>& jcurrent_url) {
-  const TemplateURL* default_provider =
-      template_url_service_->GetDefaultSearchProvider();
-
-  base::string16 query(base::android::ConvertJavaStringToUTF16(env, jquery));
-  GURL current_url(base::android::ConvertJavaStringToUTF16(env, jcurrent_url));
-  GURL destination_url(current_url);
-  if (default_provider && !query.empty()) {
-    bool refined_query = default_provider->ReplaceSearchTermsInURL(
-        current_url, TemplateURLRef::SearchTermsArgs(query),
-        template_url_service_->search_terms_data(), &destination_url);
-    if (refined_query)
-      return base::android::ConvertUTF8ToJavaString(
-          env, destination_url.spec());
-  }
-  return base::android::ScopedJavaLocalRef<jstring>(env, NULL);
-}
-
-base::android::ScopedJavaLocalRef<jstring>
 TemplateUrlServiceAndroid::GetUrlForContextualSearchQuery(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
@@ -250,8 +195,8 @@
         std::string alternate_term(
             base::android::ConvertJavaStringToUTF8(env, jalternate_term));
         if (!alternate_term.empty()) {
-          gurl = net::AppendQueryParameter(
-              gurl, "ctxsl_alternate_term", alternate_term);
+          gurl = net::AppendQueryParameter(gurl, "ctxsl_alternate_term",
+                                           alternate_term);
         }
       }
     }
@@ -310,11 +255,11 @@
   data.input_encodings.push_back("UTF-8");
   data.prepopulate_id = 0;
   data.date_created =
-      base::Time::Now() - base::TimeDelta::FromDays((int) age_in_days);
+      base::Time::Now() - base::TimeDelta::FromDays((int)age_in_days);
   data.last_modified =
-      base::Time::Now() - base::TimeDelta::FromDays((int) age_in_days);
+      base::Time::Now() - base::TimeDelta::FromDays((int)age_in_days);
   data.last_visited =
-      base::Time::Now() - base::TimeDelta::FromDays((int) age_in_days);
+      base::Time::Now() - base::TimeDelta::FromDays((int)age_in_days);
   TemplateURL* t_url =
       template_url_service_->Add(std::make_unique<TemplateURL>(data));
   CHECK(t_url) << "Failed adding template url for: " << keyword;
@@ -333,21 +278,6 @@
   return base::android::ConvertUTF16ToJavaString(env, t_url->data().keyword());
 }
 
-base::android::ScopedJavaLocalRef<jstring>
-TemplateUrlServiceAndroid::ExtractSearchTermsFromUrl(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    const base::android::JavaParamRef<jstring>& jurl) {
-  base::string16 search_terms;
-  const TemplateURL* default_search_provider =
-      template_url_service_->GetDefaultSearchProvider();
-  bool has_search_terms = default_search_provider->ExtractSearchTermsFromURL(
-      GURL(base::android::ConvertJavaStringToUTF8(jurl)),
-      template_url_service_->search_terms_data(), &search_terms);
-  return base::android::ConvertUTF16ToJavaString(
-      env, (has_search_terms ? search_terms : base::string16()));
-}
-
 void TemplateUrlServiceAndroid::GetTemplateUrls(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& obj,
@@ -373,10 +303,3 @@
   }
   return CreateTemplateUrlAndroid(env, default_search_provider);
 }
-
-static jlong JNI_TemplateUrlService_Init(JNIEnv* env,
-                                         const JavaParamRef<jobject>& obj) {
-  TemplateUrlServiceAndroid* template_url_service_android =
-      new TemplateUrlServiceAndroid(env, obj);
-  return reinterpret_cast<intptr_t>(template_url_service_android);
-}
diff --git a/chrome/browser/search_engines/template_url_service_android.h b/components/search_engines/android/template_url_service_android.h
similarity index 79%
rename from chrome/browser/search_engines/template_url_service_android.h
rename to components/search_engines/android/template_url_service_android.h
index 046bb9a1..667abb7 100644
--- a/chrome/browser/search_engines/template_url_service_android.h
+++ b/components/search_engines/android/template_url_service_android.h
@@ -2,35 +2,32 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_SERVICE_ANDROID_H_
-#define CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_SERVICE_ANDROID_H_
+#ifndef COMPONENTS_SEARCH_ENGINES_ANDROID_TEMPLATE_URL_SERVICE_ANDROID_H_
+#define COMPONENTS_SEARCH_ENGINES_ANDROID_TEMPLATE_URL_SERVICE_ANDROID_H_
 
 #include <memory>
 
-#include "base/android/jni_weak_ref.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/macros.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/search_engines/template_url_service_observer.h"
 
-class TemplateURL;
-
-
 // Android wrapper of the TemplateUrlService which provides access from the Java
 // layer. Note that on Android, there's only a single profile, and therefore
 // a single instance of this wrapper.
 class TemplateUrlServiceAndroid : public TemplateURLServiceObserver {
  public:
-  TemplateUrlServiceAndroid(JNIEnv* env, jobject obj);
+  explicit TemplateUrlServiceAndroid(TemplateURLService* template_url_service);
+  ~TemplateUrlServiceAndroid() override;
 
+  base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
   void Load(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
   void SetUserSelectedDefaultSearchProvider(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
       const base::android::JavaParamRef<jstring>& jkeyword);
-  jboolean IsLoaded(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj) const;
+  jboolean IsLoaded(JNIEnv* env,
+                    const base::android::JavaParamRef<jobject>& obj) const;
   jboolean IsDefaultSearchManaged(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
@@ -40,9 +37,6 @@
   jboolean IsDefaultSearchEngineGoogle(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
-  jboolean DoesDefaultSearchEngineHaveLogo(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj);
   jboolean IsSearchResultsPageFromDefaultSearchProvider(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
@@ -55,11 +49,6 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
       const base::android::JavaParamRef<jstring>& jquery);
-  base::android::ScopedJavaLocalRef<jstring> ReplaceSearchTermsInUrl(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jstring>& jquery,
-      const base::android::JavaParamRef<jstring>& jcurrent_url);
   base::android::ScopedJavaLocalRef<jstring> GetUrlForContextualSearchQuery(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
@@ -75,10 +64,6 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
       const base::android::JavaParamRef<jstring>& jkeyword);
-  base::android::ScopedJavaLocalRef<jstring> ExtractSearchTermsFromUrl(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jstring>& jurl);
 
   // Adds a custom search engine, sets |jkeyword| as its short_name and keyword,
   // and sets its date_created as |age_in_days| days before the current time.
@@ -108,14 +93,12 @@
       const base::android::JavaParamRef<jobject>& obj);
 
  private:
-  ~TemplateUrlServiceAndroid() override;
-
   void OnTemplateURLServiceLoaded();
 
   // TemplateUrlServiceObserver:
   void OnTemplateURLServiceChanged() override;
 
-  JavaObjectWeakGlobalRef weak_java_obj_;
+  base::android::ScopedJavaGlobalRef<jobject> java_ref_;
 
   // Pointer to the TemplateUrlService for the main profile.
   TemplateURLService* template_url_service_;
@@ -125,4 +108,4 @@
   DISALLOW_COPY_AND_ASSIGN(TemplateUrlServiceAndroid);
 };
 
-#endif  // CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_SERVICE_ANDROID_H_
+#endif  // COMPONENTS_SEARCH_ENGINES_ANDROID_TEMPLATE_URL_SERVICE_ANDROID_H_
diff --git a/components/search_engines/template_url_service.cc b/components/search_engines/template_url_service.cc
index b521df5..3537b67 100644
--- a/components/search_engines/template_url_service.cc
+++ b/components/search_engines/template_url_service.cc
@@ -33,6 +33,10 @@
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "url/gurl.h"
 
+#if defined(OS_ANDROID)
+#include "components/search_engines/android/template_url_service_android.h"
+#endif
+
 typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet;
 typedef TemplateURLService::SyncDataMap SyncDataMap;
 
@@ -324,6 +328,16 @@
   registry->RegisterBooleanPref(prefs::kDefaultSearchProviderEnabled, true);
 }
 
+#if defined(OS_ANDROID)
+base::android::ScopedJavaLocalRef<jobject> TemplateURLService::GetJavaObject() {
+  if (!template_url_service_android_) {
+    template_url_service_android_ =
+        std::make_unique<TemplateUrlServiceAndroid>(this);
+  }
+  return template_url_service_android_->GetJavaObject();
+}
+#endif
+
 bool TemplateURLService::CanAddAutogeneratedKeyword(
     const base::string16& keyword,
     const GURL& url,
diff --git a/components/search_engines/template_url_service.h b/components/search_engines/template_url_service.h
index 879aaeb..8c03c40f 100644
--- a/components/search_engines/template_url_service.h
+++ b/components/search_engines/template_url_service.h
@@ -20,6 +20,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/time/default_clock.h"
+#include "build/build_config.h"
 #include "components/google/core/browser/google_url_tracker.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -31,12 +32,18 @@
 #include "components/sync/model/sync_change.h"
 #include "components/sync/model/syncable_service.h"
 #include "components/webdata/common/web_data_service_consumer.h"
+#if defined(OS_ANDROID)
+#include "base/android/scoped_java_ref.h"
+#endif
 
 class GURL;
 class PrefService;
 class TemplateURLServiceClient;
 class TemplateURLServiceObserver;
 struct TemplateURLData;
+#if defined(OS_ANDROID)
+class TemplateUrlServiceAndroid;
+#endif
 
 namespace rappor {
 class RapporServiceImpl;
@@ -116,6 +123,10 @@
   // Register Profile preferences in |registry|.
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
+#if defined(OS_ANDROID)
+  base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
+#endif
+
   // Returns true if there is no TemplateURL that conflicts with the
   // keyword/url pair, or there is one but it can be replaced. If there is an
   // existing keyword that can be replaced and template_url_to_replace is
@@ -852,6 +863,12 @@
   // but if no model mutation occurs, the deferred notification can be skipped.
   bool model_mutated_notification_pending_ = false;
 
+#if defined(OS_ANDROID)
+  // Manage and fetch the java object that wraps this TemplateURLService on
+  // android.
+  std::unique_ptr<TemplateUrlServiceAndroid> template_url_service_android_;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(TemplateURLService);
 };
 
diff --git a/components/sessions/ios/ios_serialized_navigation_builder.mm b/components/sessions/ios/ios_serialized_navigation_builder.mm
index 70fc1530..9f0cd7a 100644
--- a/components/sessions/ios/ios_serialized_navigation_builder.mm
+++ b/components/sessions/ios/ios_serialized_navigation_builder.mm
@@ -5,7 +5,7 @@
 #include "components/sessions/ios/ios_serialized_navigation_builder.h"
 
 #include "components/sessions/core/serialized_navigation_entry.h"
-#include "ios/web/public/favicon_status.h"
+#include "ios/web/public/favicon/favicon_status.h"
 #include "ios/web/public/navigation_item.h"
 #include "ios/web/public/referrer.h"
 
diff --git a/components/sessions/ios/ios_serialized_navigation_builder_unittest.mm b/components/sessions/ios/ios_serialized_navigation_builder_unittest.mm
index da0dcb6..d791239 100644
--- a/components/sessions/ios/ios_serialized_navigation_builder_unittest.mm
+++ b/components/sessions/ios/ios_serialized_navigation_builder_unittest.mm
@@ -6,7 +6,7 @@
 
 #include "components/sessions/core/serialized_navigation_entry.h"
 #include "components/sessions/core/serialized_navigation_entry_test_helper.h"
-#include "ios/web/public/favicon_status.h"
+#include "ios/web/public/favicon/favicon_status.h"
 #include "ios/web/public/navigation_item.h"
 #include "ios/web/public/referrer.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/signin/core/browser/BUILD.gn b/components/signin/core/browser/BUILD.gn
index 5bbd4e0..506e781 100644
--- a/components/signin/core/browser/BUILD.gn
+++ b/components/signin/core/browser/BUILD.gn
@@ -87,7 +87,6 @@
     "oauth_multilogin_token_fetcher.h",
     "primary_account_manager.cc",
     "primary_account_manager.h",
-    "primary_account_policy_manager.cc",
     "primary_account_policy_manager.h",
     "profile_oauth2_token_service.cc",
     "profile_oauth2_token_service.h",
@@ -99,8 +98,11 @@
     "ubertoken_fetcher_impl.h",
   ]
 
-  if (is_chromeos) {
-    sources -= [ "primary_account_policy_manager.cc" ]
+  if (!is_chromeos) {
+    sources += [
+      "primary_account_policy_manager_impl.cc",
+      "primary_account_policy_manager_impl.h",
+    ]
   }
 
   deps = [
diff --git a/components/signin/core/browser/primary_account_manager.cc b/components/signin/core/browser/primary_account_manager.cc
index 4c790db3e..d7f70f4d 100644
--- a/components/signin/core/browser/primary_account_manager.cc
+++ b/components/signin/core/browser/primary_account_manager.cc
@@ -4,37 +4,39 @@
 
 #include "components/signin/core/browser/primary_account_manager.h"
 
+#include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/command_line.h"
-#include "base/memory/ref_counted.h"
+#include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/account_info.h"
 #include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/primary_account_policy_manager.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_client.h"
+#include "components/signin/core/browser/signin_metrics.h"
 #include "components/signin/core/browser/signin_pref_names.h"
 #include "components/signin/core/browser/signin_switches.h"
-#include "google_apis/gaia/gaia_auth_util.h"
-#include "google_apis/gaia/gaia_constants.h"
-#include "google_apis/gaia/gaia_urls.h"
 
 PrimaryAccountManager::PrimaryAccountManager(
     SigninClient* client,
     ProfileOAuth2TokenService* token_service,
     AccountTrackerService* account_tracker_service,
-    signin::AccountConsistencyMethod account_consistency)
+    signin::AccountConsistencyMethod account_consistency,
+    std::unique_ptr<PrimaryAccountPolicyManager> policy_manager)
     : client_(client),
       token_service_(token_service),
       account_tracker_service_(account_tracker_service),
       initialized_(false),
-      account_consistency_(account_consistency) {
+#if !defined(OS_CHROMEOS)
+      account_consistency_(account_consistency),
+#endif
+      policy_manager_(std::move(policy_manager)) {
   DCHECK(client_);
   DCHECK(account_tracker_service_);
 }
@@ -155,16 +157,15 @@
     }
     SetAuthenticatedAccountId(CoreAccountId(pref_account_id));
   }
-  FinalizeInitBeforeLoadingRefreshTokens(local_state);
+  if (policy_manager_) {
+    policy_manager_->InitializePolicy(local_state, this);
+  }
   // It is important to only load credentials after starting to observe the
   // token service.
   token_service_->AddObserver(this);
   token_service_->LoadCredentials(GetAuthenticatedAccountId());
 }
 
-void PrimaryAccountManager::FinalizeInitBeforeLoadingRefreshTokens(
-    PrefService* local_state) {}
-
 bool PrimaryAccountManager::IsInitialized() const {
   return initialized_;
 }
@@ -263,7 +264,7 @@
 
   bool reauth_in_progress = IsAuthenticated();
 
-  signin_client()->GetPrefs()->SetInt64(
+  client_->GetPrefs()->SetInt64(
       prefs::kSignedInTime,
       base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
 
@@ -272,8 +273,8 @@
   if (!reauth_in_progress && observer_ != nullptr)
     observer_->GoogleSigninSucceeded(GetAuthenticatedAccountInfo());
 
-  signin_metrics::LogSigninProfile(signin_client()->IsFirstRun(),
-                                   signin_client()->GetInstallDate());
+  signin_metrics::LogSigninProfile(client_->IsFirstRun(),
+                                   client_->GetInstallDate());
 }
 
 void PrimaryAccountManager::SignOut(
@@ -307,7 +308,7 @@
   VLOG(1) << "StartSignOut: " << static_cast<int>(signout_source_metric) << ", "
           << static_cast<int>(signout_delete_metric) << ", "
           << static_cast<int>(remove_option);
-  signin_client()->PreSignOut(
+  client_->PreSignOut(
       base::BindOnce(&PrimaryAccountManager::OnSignoutDecisionReached,
                      base::Unretained(this), signout_source_metric,
                      signout_delete_metric, remove_option),
@@ -340,12 +341,12 @@
   const std::string username = account_info.email;
   const base::Time signin_time =
       base::Time::FromDeltaSinceWindowsEpoch(base::TimeDelta::FromMicroseconds(
-          signin_client()->GetPrefs()->GetInt64(prefs::kSignedInTime)));
+          client_->GetPrefs()->GetInt64(prefs::kSignedInTime)));
   ClearAuthenticatedAccountId();
-  signin_client()->GetPrefs()->ClearPref(prefs::kGoogleServicesHostedDomain);
-  signin_client()->GetPrefs()->ClearPref(prefs::kGoogleServicesAccountId);
-  signin_client()->GetPrefs()->ClearPref(prefs::kGoogleServicesUserAccountId);
-  signin_client()->GetPrefs()->ClearPref(prefs::kSignedInTime);
+  client_->GetPrefs()->ClearPref(prefs::kGoogleServicesHostedDomain);
+  client_->GetPrefs()->ClearPref(prefs::kGoogleServicesAccountId);
+  client_->GetPrefs()->ClearPref(prefs::kGoogleServicesUserAccountId);
+  client_->GetPrefs()->ClearPref(prefs::kSignedInTime);
 
   // Determine the duration the user was logged in and log that to UMA.
   if (!signin_time.is_null()) {
diff --git a/components/signin/core/browser/primary_account_manager.h b/components/signin/core/browser/primary_account_manager.h
index 2999661..f7f8c20 100644
--- a/components/signin/core/browser/primary_account_manager.h
+++ b/components/signin/core/browser/primary_account_manager.h
@@ -22,23 +22,22 @@
 #include <string>
 
 #include "base/callback_list.h"
-#include "base/compiler_specific.h"
-#include "base/logging.h"
 #include "base/macros.h"
-#include "base/observer_list.h"
-#include "components/prefs/pref_change_registrar.h"
-#include "components/prefs/pref_member.h"
 #include "components/signin/core/browser/account_consistency_method.h"
-#include "components/signin/core/browser/account_info.h"
 #include "components/signin/core/browser/signin_client.h"
-#include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 
+struct AccountInfo;
 class AccountTrackerService;
 class PrefRegistrySimple;
 class PrefService;
+class PrimaryAccountPolicyManager;
 class ProfileOAuth2TokenService;
-class SigninClient;
+
+namespace signin_metrics {
+enum ProfileSignout;
+enum class SignoutDelete;
+}  // namespace signin_metrics
 
 class PrimaryAccountManager : public OAuth2TokenServiceObserver {
  public:
@@ -63,24 +62,6 @@
     virtual ~Observer() {}
   };
 
-// On non-ChromeOS platforms, PrimaryAccountManager should only be instantiated
-// via the derived PrimaryAccountPolicyManager class, as the codewise assumes
-// the invariant that any PrimaryAccountManager object can be cast to a
-// PrimaryAccountPolicyManager object when not on ChromeOS. Make the constructor
-// private and add PrimaryAccountPolicyManager as a friend to support this.
-// TODO(952766): Eliminate this once the functionality of PrimaryAccountManager
-// and PrimaryAccountPolicyManager is merged.
-#if !defined(OS_CHROMEOS)
- private:
-#endif
-  PrimaryAccountManager(SigninClient* client,
-                        ProfileOAuth2TokenService* token_service,
-                        AccountTrackerService* account_tracker_service,
-                        signin::AccountConsistencyMethod account_consistency);
-#if !defined(OS_CHROMEOS)
- public:
-#endif
-
 #if !defined(OS_CHROMEOS)
   // Used to remove accounts from the token service and the account tracker.
   enum class RemoveAccountsOption {
@@ -93,6 +74,12 @@
   };
 #endif
 
+  PrimaryAccountManager(
+      SigninClient* client,
+      ProfileOAuth2TokenService* token_service,
+      AccountTrackerService* account_tracker_service,
+      signin::AccountConsistencyMethod account_consistency,
+      std::unique_ptr<PrimaryAccountPolicyManager> policy_manager);
   ~PrimaryAccountManager() override;
 
   // Registers per-profile prefs.
@@ -174,19 +161,7 @@
       signin_metrics::SignoutDelete signout_delete_metric);
 #endif
 
- protected:
-  SigninClient* signin_client() const { return client_; }
-
-  // Invoked at the end of |Initialize| before the refresh token for the primary
-  // account is loaded.
-  virtual void FinalizeInitBeforeLoadingRefreshTokens(PrefService* local_state);
-
  private:
-  // Added only to allow PrimaryAccountPolicyManager to call the
-  // PrimaryAccountManager constructor while disallowing any ad-hoc subclassing
-  // of PrimaryAccountManager.
-  friend class PrimaryAccountPolicyManager;
-
   // Sets the authenticated user's account id.
   // If the user is already authenticated with the same account id, then this
   // method is a no-op.
@@ -242,7 +217,11 @@
   // The list of callbacks notified on shutdown.
   base::CallbackList<void()> on_shutdown_callback_list_;
 
+#if !defined(OS_CHROMEOS)
   signin::AccountConsistencyMethod account_consistency_;
+#endif
+
+  std::unique_ptr<PrimaryAccountPolicyManager> policy_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(PrimaryAccountManager);
 };
diff --git a/components/signin/core/browser/primary_account_manager_unittest.cc b/components/signin/core/browser/primary_account_manager_unittest.cc
index 286b0c2..561b8da 100644
--- a/components/signin/core/browser/primary_account_manager_unittest.cc
+++ b/components/signin/core/browser/primary_account_manager_unittest.cc
@@ -2,18 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/signin/core/browser/primary_account_policy_manager.h"
+#include "components/signin/core/browser/primary_account_manager.h"
 
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/compiler_specific.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
-#include "build/build_config.h"
 #include "components/image_fetcher/core/fake_image_decoder.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
@@ -22,15 +19,12 @@
 #include "components/signin/core/browser/account_consistency_method.h"
 #include "components/signin/core/browser/account_fetcher_service.h"
 #include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/device_id_helper.h"
+#include "components/signin/core/browser/primary_account_policy_manager_impl.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_pref_names.h"
 #include "components/signin/core/browser/test_signin_client.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "google_apis/gaia/fake_oauth2_token_service_delegate.h"
-#include "google_apis/gaia/gaia_urls.h"
-#include "net/cookies/cookie_monster.h"
-#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -93,7 +87,7 @@
   PrefService* prefs() { return &user_prefs_; }
 
   // Seed the account tracker with information from logged in user.  Normally
-  // this is done by UI code before calling PrimaryAccountPolicyManager.
+  // this is done by UI code before calling PrimaryAccountManager.
   // Returns the string to use as the account_id.
   std::string AddToAccountTracker(const std::string& gaia_id,
                                   const std::string& email) {
@@ -105,9 +99,12 @@
   // needed.
   void CreatePrimaryAccountManager() {
     DCHECK(!manager_);
-    manager_ = std::make_unique<PrimaryAccountPolicyManager>(
+    auto policy_manager =
+        std::make_unique<PrimaryAccountPolicyManagerImpl>(&test_signin_client_);
+    policy_manager_ = policy_manager.get();
+    manager_ = std::make_unique<PrimaryAccountManager>(
         &test_signin_client_, &token_service_, &account_tracker_,
-        account_consistency_);
+        account_consistency_, std::move(policy_manager));
     manager_->Initialize(&local_state_);
     manager_->SetObserver(&test_observer_);
   }
@@ -138,7 +135,8 @@
   ProfileOAuth2TokenService token_service_;
   AccountTrackerService account_tracker_;
   AccountFetcherService account_fetcher_;
-  std::unique_ptr<PrimaryAccountPolicyManager> manager_;
+  PrimaryAccountPolicyManagerImpl* policy_manager_;
+  std::unique_ptr<PrimaryAccountManager> manager_;
   TestPrimaryAccountManagerObserver test_observer_;
   std::vector<std::string> oauth_tokens_fetched_;
   std::vector<std::string> cookies_;
@@ -257,11 +255,11 @@
   local_state_.SetString(prefs::kGoogleServicesUsernamePattern,
                          ".*@google.com");
   CreatePrimaryAccountManager();
-  EXPECT_TRUE(manager_->IsAllowedUsername("test@google.com"));
-  EXPECT_TRUE(manager_->IsAllowedUsername("happy@google.com"));
-  EXPECT_FALSE(manager_->IsAllowedUsername("test@invalid.com"));
-  EXPECT_FALSE(manager_->IsAllowedUsername("test@notgoogle.com"));
-  EXPECT_FALSE(manager_->IsAllowedUsername(std::string()));
+  EXPECT_TRUE(policy_manager_->IsAllowedUsername("test@google.com"));
+  EXPECT_TRUE(policy_manager_->IsAllowedUsername("happy@google.com"));
+  EXPECT_FALSE(policy_manager_->IsAllowedUsername("test@invalid.com"));
+  EXPECT_FALSE(policy_manager_->IsAllowedUsername("test@notgoogle.com"));
+  EXPECT_FALSE(policy_manager_->IsAllowedUsername(std::string()));
 }
 
 TEST_F(PrimaryAccountManagerTest, TestAlternateWildcard) {
@@ -269,11 +267,11 @@
   // the admin entered ".*@google.com").
   local_state_.SetString(prefs::kGoogleServicesUsernamePattern, "*@google.com");
   CreatePrimaryAccountManager();
-  EXPECT_TRUE(manager_->IsAllowedUsername("test@google.com"));
-  EXPECT_TRUE(manager_->IsAllowedUsername("happy@google.com"));
-  EXPECT_FALSE(manager_->IsAllowedUsername("test@invalid.com"));
-  EXPECT_FALSE(manager_->IsAllowedUsername("test@notgoogle.com"));
-  EXPECT_FALSE(manager_->IsAllowedUsername(std::string()));
+  EXPECT_TRUE(policy_manager_->IsAllowedUsername("test@google.com"));
+  EXPECT_TRUE(policy_manager_->IsAllowedUsername("happy@google.com"));
+  EXPECT_FALSE(policy_manager_->IsAllowedUsername("test@invalid.com"));
+  EXPECT_FALSE(policy_manager_->IsAllowedUsername("test@notgoogle.com"));
+  EXPECT_FALSE(policy_manager_->IsAllowedUsername(std::string()));
 }
 
 TEST_F(PrimaryAccountManagerTest, ProhibitedAtStartup) {
diff --git a/components/signin/core/browser/primary_account_policy_manager.cc b/components/signin/core/browser/primary_account_policy_manager.cc
deleted file mode 100644
index 3bea908..0000000
--- a/components/signin/core/browser/primary_account_policy_manager.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/signin/core/browser/primary_account_policy_manager.h"
-
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "components/prefs/pref_service.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/identity_utils.h"
-#include "components/signin/core/browser/signin_metrics.h"
-#include "components/signin/core/browser/signin_pref_names.h"
-#include "google_apis/gaia/gaia_auth_util.h"
-#include "google_apis/gaia/gaia_constants.h"
-#include "google_apis/gaia/gaia_urls.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-#include "third_party/icu/source/i18n/unicode/regex.h"
-
-PrimaryAccountPolicyManager::PrimaryAccountPolicyManager(
-    SigninClient* client,
-    ProfileOAuth2TokenService* token_service,
-    AccountTrackerService* account_tracker_service,
-    signin::AccountConsistencyMethod account_consistency)
-    : PrimaryAccountManager(client,
-                            token_service,
-                            account_tracker_service,
-                            account_consistency),
-      weak_pointer_factory_(this) {}
-
-PrimaryAccountPolicyManager::~PrimaryAccountPolicyManager() {
-  local_state_pref_registrar_.RemoveAll();
-}
-
-void PrimaryAccountPolicyManager::FinalizeInitBeforeLoadingRefreshTokens(
-    PrefService* local_state) {
-  // local_state can be null during unit tests.
-  if (local_state) {
-    local_state_pref_registrar_.Init(local_state);
-    local_state_pref_registrar_.Add(
-        prefs::kGoogleServicesUsernamePattern,
-        base::Bind(&PrimaryAccountPolicyManager::
-                       OnGoogleServicesUsernamePatternChanged,
-                   weak_pointer_factory_.GetWeakPtr()));
-  }
-  signin_allowed_.Init(
-      prefs::kSigninAllowed, signin_client()->GetPrefs(),
-      base::Bind(&PrimaryAccountPolicyManager::OnSigninAllowedPrefChanged,
-                 base::Unretained(this)));
-
-  AccountInfo account_info = GetAuthenticatedAccountInfo();
-  if (!account_info.account_id.empty() &&
-      (!IsAllowedUsername(account_info.email) || !IsSigninAllowed())) {
-    // User is signed in, but the username is invalid or signin is no longer
-    // allowed, so the user must be sign out.
-    //
-    // This may happen in the following cases:
-    //   a. The user has toggled off signin allowed in settings.
-    //   b. The administrator changed the policy since the last signin.
-    //
-    // Note: The token service has not yet loaded its credentials, so accounts
-    // cannot be revoked here.
-    //
-    // On desktop, when PrimaryAccountManager is initializing, the profile was
-    // not yet marked with sign out allowed. Therefore sign out is not allowed
-    // and all calls to SignOut methods are no-op.
-    //
-    // TODO(msarda): SignOut methods do not guarantee that sign out can actually
-    // be done (this depends on whether sign out is allowed). Add a check here
-    // on desktop to make it clear that SignOut does not do anything.
-    SignOutAndKeepAllAccounts(signin_metrics::SIGNIN_PREF_CHANGED_DURING_SIGNIN,
-                              signin_metrics::SignoutDelete::IGNORE_METRIC);
-  }
-}
-
-void PrimaryAccountPolicyManager::OnGoogleServicesUsernamePatternChanged() {
-  if (IsAuthenticated() &&
-      !IsAllowedUsername(GetAuthenticatedAccountInfo().email)) {
-    // Signed in user is invalid according to the current policy so sign
-    // the user out.
-    SignOut(signin_metrics::GOOGLE_SERVICE_NAME_PATTERN_CHANGED,
-            signin_metrics::SignoutDelete::IGNORE_METRIC);
-  }
-}
-
-bool PrimaryAccountPolicyManager::IsSigninAllowed() const {
-  return signin_allowed_.GetValue();
-}
-
-void PrimaryAccountPolicyManager::OnSigninAllowedPrefChanged() {
-  if (!IsSigninAllowed() && IsAuthenticated()) {
-    VLOG(0) << "IsSigninAllowed() set to false, signing out the user";
-    SignOut(signin_metrics::SIGNOUT_PREF_CHANGED,
-            signin_metrics::SignoutDelete::IGNORE_METRIC);
-  }
-}
-
-bool PrimaryAccountPolicyManager::IsAllowedUsername(
-    const std::string& username) const {
-  const PrefService* local_state = local_state_pref_registrar_.prefs();
-  if (!local_state)
-    return true;  // In a unit test with no local state - all names are allowed.
-
-  std::string pattern =
-      local_state->GetString(prefs::kGoogleServicesUsernamePattern);
-  return identity::IsUsernameAllowedByPattern(username, pattern);
-}
diff --git a/components/signin/core/browser/primary_account_policy_manager.h b/components/signin/core/browser/primary_account_policy_manager.h
index 2e054c5..a0a9169 100644
--- a/components/signin/core/browser/primary_account_policy_manager.h
+++ b/components/signin/core/browser/primary_account_policy_manager.h
@@ -1,89 +1,29 @@
 // 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.
-//
-// The signin manager encapsulates some functionality tracking which user is
-// signed in. See PrimaryAccountManager for full description of
-// responsibilities. The class defined in this file provides functionality
-// required by all platforms except Chrome OS.
 
 #ifndef COMPONENTS_SIGNIN_CORE_BROWSER_PRIMARY_ACCOUNT_POLICY_MANAGER_H_
 #define COMPONENTS_SIGNIN_CORE_BROWSER_PRIMARY_ACCOUNT_POLICY_MANAGER_H_
 
-#include "build/build_config.h"
-
-#if defined(OS_CHROMEOS)
-
-#include "components/signin/core/browser/primary_account_manager.h"
-
-#else
-
-#include <set>
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/gtest_prod_util.h"
-#include "base/logging.h"
 #include "base/macros.h"
-#include "base/observer_list.h"
-#include "base/strings/string_piece.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "components/prefs/pref_change_registrar.h"
-#include "components/prefs/pref_member.h"
-#include "components/signin/core/browser/account_info.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/primary_account_manager.h"
-#include "components/signin/core/browser/signin_metrics.h"
-#include "net/cookies/canonical_cookie.h"
 
 class PrefService;
-class ProfileOAuth2TokenService;
+class PrimaryAccountManager;
 
-namespace identity {
-class IdentityManager;
-}  // namespace identity
-
-class PrimaryAccountPolicyManager : public PrimaryAccountManager {
+class PrimaryAccountPolicyManager {
  public:
-  PrimaryAccountPolicyManager(
-      SigninClient* client,
-      ProfileOAuth2TokenService* token_service,
-      AccountTrackerService* account_tracker_service,
-      signin::AccountConsistencyMethod account_consistency);
-  ~PrimaryAccountPolicyManager() override;
+  PrimaryAccountPolicyManager() = default;
+  virtual ~PrimaryAccountPolicyManager() = default;
 
   // On platforms where PrimaryAccountManager is responsible for dealing with
   // invalid username policy updates, we need to check this during
   // initialization and sign the user out.
-  void FinalizeInitBeforeLoadingRefreshTokens(
-      PrefService* local_state) override;
+  virtual void InitializePolicy(
+      PrefService* local_state,
+      PrimaryAccountManager* primary_account_manager) = 0;
 
  private:
-  friend class identity::IdentityManager;
-  FRIEND_TEST_ALL_PREFIXES(PrimaryAccountManagerTest, Prohibited);
-  FRIEND_TEST_ALL_PREFIXES(PrimaryAccountManagerTest, TestAlternateWildcard);
-
-  // Returns true if a signin to Chrome is allowed (by policy or pref).
-  bool IsSigninAllowed() const;
-
-  void OnSigninAllowedPrefChanged();
-  void OnGoogleServicesUsernamePatternChanged();
-
-  // Returns true if the passed username is allowed by policy.
-  bool IsAllowedUsername(const std::string& username) const;
-
-  // Helper object to listen for changes to signin preferences stored in non-
-  // profile-specific local prefs (like kGoogleServicesUsernamePattern).
-  PrefChangeRegistrar local_state_pref_registrar_;
-
-  // Helper object to listen for changes to the signin allowed preference.
-  BooleanPrefMember signin_allowed_;
-
-  base::WeakPtrFactory<PrimaryAccountPolicyManager> weak_pointer_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(PrimaryAccountPolicyManager);
 };
 
-#endif  // !defined(OS_CHROMEOS)
-
 #endif  // COMPONENTS_SIGNIN_CORE_BROWSER_PRIMARY_ACCOUNT_POLICY_MANAGER_H_
diff --git a/components/signin/core/browser/primary_account_policy_manager_impl.cc b/components/signin/core/browser/primary_account_policy_manager_impl.cc
new file mode 100644
index 0000000..b1cff7d
--- /dev/null
+++ b/components/signin/core/browser/primary_account_policy_manager_impl.cc
@@ -0,0 +1,109 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/signin/core/browser/primary_account_policy_manager_impl.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "components/prefs/pref_member.h"
+#include "components/prefs/pref_service.h"
+#include "components/signin/core/browser/identity_utils.h"
+#include "components/signin/core/browser/primary_account_manager.h"
+#include "components/signin/core/browser/signin_client.h"
+#include "components/signin/core/browser/signin_metrics.h"
+#include "components/signin/core/browser/signin_pref_names.h"
+
+PrimaryAccountPolicyManagerImpl::PrimaryAccountPolicyManagerImpl(
+    SigninClient* client)
+    : client_(client), weak_pointer_factory_(this) {}
+
+PrimaryAccountPolicyManagerImpl::~PrimaryAccountPolicyManagerImpl() {
+  local_state_pref_registrar_.RemoveAll();
+}
+
+void PrimaryAccountPolicyManagerImpl::InitializePolicy(
+    PrefService* local_state,
+    PrimaryAccountManager* primary_account_manager) {
+  // local_state can be null during unit tests.
+  if (local_state) {
+    local_state_pref_registrar_.Init(local_state);
+    local_state_pref_registrar_.Add(
+        prefs::kGoogleServicesUsernamePattern,
+        base::Bind(&PrimaryAccountPolicyManagerImpl::
+                       OnGoogleServicesUsernamePatternChanged,
+                   weak_pointer_factory_.GetWeakPtr(),
+                   primary_account_manager));
+  }
+  signin_allowed_.Init(
+      prefs::kSigninAllowed, client_->GetPrefs(),
+      base::Bind(&PrimaryAccountPolicyManagerImpl::OnSigninAllowedPrefChanged,
+                 base::Unretained(this), primary_account_manager));
+
+  AccountInfo account_info =
+      primary_account_manager->GetAuthenticatedAccountInfo();
+  if (!account_info.account_id.empty() &&
+      (!IsAllowedUsername(account_info.email) || !IsSigninAllowed())) {
+    // User is signed in, but the username is invalid or signin is no longer
+    // allowed, so the user must be sign out.
+    //
+    // This may happen in the following cases:
+    //   a. The user has toggled off signin allowed in settings.
+    //   b. The administrator changed the policy since the last signin.
+    //
+    // Note: The token service has not yet loaded its credentials, so accounts
+    // cannot be revoked here.
+    //
+    // On desktop, when PrimaryAccountManager is initializing, the profile was
+    // not yet marked with sign out allowed. Therefore sign out is not allowed
+    // and all calls to SignOut methods are no-op.
+    //
+    // TODO(msarda): SignOut methods do not guarantee that sign out can actually
+    // be done (this depends on whether sign out is allowed). Add a check here
+    // on desktop to make it clear that SignOut does not do anything.
+    primary_account_manager->SignOutAndKeepAllAccounts(
+        signin_metrics::SIGNIN_PREF_CHANGED_DURING_SIGNIN,
+        signin_metrics::SignoutDelete::IGNORE_METRIC);
+  }
+}
+
+void PrimaryAccountPolicyManagerImpl::OnGoogleServicesUsernamePatternChanged(
+    PrimaryAccountManager* primary_account_manager) {
+  if (primary_account_manager->IsAuthenticated() &&
+      !IsAllowedUsername(
+          primary_account_manager->GetAuthenticatedAccountInfo().email)) {
+    // Signed in user is invalid according to the current policy so sign
+    // the user out.
+    primary_account_manager->SignOut(
+        signin_metrics::GOOGLE_SERVICE_NAME_PATTERN_CHANGED,
+        signin_metrics::SignoutDelete::IGNORE_METRIC);
+  }
+}
+
+bool PrimaryAccountPolicyManagerImpl::IsSigninAllowed() const {
+  return signin_allowed_.GetValue();
+}
+
+void PrimaryAccountPolicyManagerImpl::OnSigninAllowedPrefChanged(
+    PrimaryAccountManager* primary_account_manager) {
+  if (!IsSigninAllowed() && primary_account_manager->IsAuthenticated()) {
+    VLOG(0) << "IsSigninAllowed() set to false, signing out the user";
+    primary_account_manager->SignOut(
+        signin_metrics::SIGNOUT_PREF_CHANGED,
+        signin_metrics::SignoutDelete::IGNORE_METRIC);
+  }
+}
+
+bool PrimaryAccountPolicyManagerImpl::IsAllowedUsername(
+    const std::string& username) const {
+  const PrefService* local_state = local_state_pref_registrar_.prefs();
+  if (!local_state)
+    return true;  // In a unit test with no local state - all names are allowed.
+
+  std::string pattern =
+      local_state->GetString(prefs::kGoogleServicesUsernamePattern);
+  return identity::IsUsernameAllowedByPattern(username, pattern);
+}
diff --git a/components/signin/core/browser/primary_account_policy_manager_impl.h b/components/signin/core/browser/primary_account_policy_manager_impl.h
new file mode 100644
index 0000000..d6e2451d
--- /dev/null
+++ b/components/signin/core/browser/primary_account_policy_manager_impl.h
@@ -0,0 +1,62 @@
+// 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.
+//
+// This class is only built in Chrome OS.
+
+#ifndef COMPONENTS_SIGNIN_CORE_BROWSER_PRIMARY_ACCOUNT_POLICY_MANAGER_IMPL_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_PRIMARY_ACCOUNT_POLICY_MANAGER_IMPL_H_
+
+#include <string>
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "components/prefs/pref_member.h"
+#include "components/signin/core/browser/primary_account_policy_manager.h"
+
+class PrefService;
+class PrimaryAccountManager;
+class SigninClient;
+
+class PrimaryAccountPolicyManagerImpl : public PrimaryAccountPolicyManager {
+ public:
+  explicit PrimaryAccountPolicyManagerImpl(SigninClient* client);
+  ~PrimaryAccountPolicyManagerImpl() override;
+
+  // PrimaryAccountPolicyManager:
+  void InitializePolicy(
+      PrefService* local_state,
+      PrimaryAccountManager* primary_account_manager) override;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(PrimaryAccountManagerTest, Prohibited);
+  FRIEND_TEST_ALL_PREFIXES(PrimaryAccountManagerTest, TestAlternateWildcard);
+
+  // Returns true if a signin to Chrome is allowed (by policy or pref).
+  bool IsSigninAllowed() const;
+
+  void OnSigninAllowedPrefChanged(
+      PrimaryAccountManager* primary_account_manager);
+  void OnGoogleServicesUsernamePatternChanged(
+      PrimaryAccountManager* primary_account_manager);
+
+  // Returns true if the passed username is allowed by policy.
+  bool IsAllowedUsername(const std::string& username) const;
+
+  SigninClient* client_;
+
+  // Helper object to listen for changes to signin preferences stored in non-
+  // profile-specific local prefs (like kGoogleServicesUsernamePattern).
+  PrefChangeRegistrar local_state_pref_registrar_;
+
+  // Helper object to listen for changes to the signin allowed preference.
+  BooleanPrefMember signin_allowed_;
+
+  base::WeakPtrFactory<PrimaryAccountPolicyManagerImpl> weak_pointer_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrimaryAccountPolicyManagerImpl);
+};
+
+#endif  // COMPONENTS_SIGNIN_CORE_BROWSER_PRIMARY_ACCOUNT_POLICY_MANAGER_IMPL_H_
diff --git a/components/signin/ios/browser/active_state_manager_impl.mm b/components/signin/ios/browser/active_state_manager_impl.mm
index 26a7fc57..494c88e2 100644
--- a/components/signin/ios/browser/active_state_manager_impl.mm
+++ b/components/signin/ios/browser/active_state_manager_impl.mm
@@ -7,7 +7,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "ios/web/public/browser_state.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/components/vector_icons/screen_share.icon b/components/vector_icons/screen_share.icon
index 32b8cfc..dd1884b 100644
--- a/components/vector_icons/screen_share.icon
+++ b/components/vector_icons/screen_share.icon
@@ -2,28 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-CANVAS_DIMENSIONS, 32,
-MOVE_TO, 4.62f, 6,
-CUBIC_TO, 3.18f, 6, 2, 7.14f, 2, 8.54f,
-V_LINE_TO, 23.77f,
-CUBIC_TO, 2, 25.17f, 3.18f, 26, 4.62f, 26,
-R_H_LINE_TO, 22.77f,
-CUBIC_TO, 28.82f, 26, 30, 25.17f, 30, 23.77f,
-V_LINE_TO, 8.54f,
-CUBIC_TO, 30, 7.14f, 28.82f, 6, 27.38f, 6,
-H_LINE_TO, 4.62f,
+MOVE_TO, 40, 36,
+R_CUBIC_TO, 2.2f, 0, 3.98f, -1.8f, 3.98f, -4,
+LINE_TO, 44, 12,
+R_CUBIC_TO, 0, -2.22f, -1.8f, -4, -4, -4,
+H_LINE_TO, 8,
+R_CUBIC_TO, -2.22f, 0, -4, 1.78f, -4, 4,
+R_V_LINE_TO, 20,
+R_CUBIC_TO, 0, 2.2f, 1.78f, 4, 4, 4,
+H_LINE_TO, 0,
+R_V_LINE_TO, 4,
+R_H_LINE_TO, 48,
+R_V_LINE_TO, -4,
+R_H_LINE_TO, -8,
 CLOSE,
-MOVE_TO, 4, 24,
-V_LINE_TO, 8,
-R_H_LINE_TO, 24,
-R_V_LINE_TO, 16,
-H_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 13, -7,
-R_CUBIC_TO, -3.64f, -0.06f, -5.33f, 0.9f, -7, 3,
-R_CUBIC_TO, 0.67f, -3, 2.03f, -6, 7, -6,
-R_V_LINE_TO, -3,
-R_LINE_TO, 5.5f, 4.5f,
-LINE_TO, 17, 20,
-R_V_LINE_TO, -3,
+R_MOVE_TO, -14, -7.06f,
+R_V_LINE_TO, -4.38f,
+R_CUBIC_TO, -5.56f, 0, -9.22f, 1.7f, -12, 5.44f,
+R_CUBIC_TO, 1.12f, -5.34f, 4.22f, -10.66f, 12, -11.74f,
+V_LINE_TO, 14,
+R_LINE_TO, 8, 7.46f,
+R_LINE_TO, -8, 7.48f,
 CLOSE
diff --git a/components/viz/common/gpu/vulkan_in_process_context_provider.cc b/components/viz/common/gpu/vulkan_in_process_context_provider.cc
index 1e685b26..bec98f4 100644
--- a/components/viz/common/gpu/vulkan_in_process_context_provider.cc
+++ b/components/viz/common/gpu/vulkan_in_process_context_provider.cc
@@ -34,14 +34,6 @@
   };
 }
 
-VulkanInProcessContextProvider::VulkanInProcessContextProvider(
-    gpu::VulkanImplementation* vulkan_implementation)
-    : vulkan_implementation_(vulkan_implementation) {}
-
-VulkanInProcessContextProvider::~VulkanInProcessContextProvider() {
-  Destroy();
-}
-
 bool VulkanInProcessContextProvider::Initialize() {
   DCHECK(!device_queue_);
   const gfx::ExtensionSet& extensions =
@@ -97,12 +89,8 @@
 }
 
 void VulkanInProcessContextProvider::Destroy() {
-  if (gr_context_) {
-    // releaseResourcesAndAbandonContext() will wait on GPU to finish all works,
-    // execute pending flush done callbacks and release all resources.
-    gr_context_->releaseResourcesAndAbandonContext();
+  if (gr_context_)
     gr_context_.reset();
-  }
 
   if (device_queue_) {
     device_queue_->Destroy();
@@ -138,4 +126,12 @@
   NOTREACHED();
 }
 
+VulkanInProcessContextProvider::VulkanInProcessContextProvider(
+    gpu::VulkanImplementation* vulkan_implementation)
+    : vulkan_implementation_(vulkan_implementation) {}
+
+VulkanInProcessContextProvider::~VulkanInProcessContextProvider() {
+  Destroy();
+}
+
 }  // namespace viz
diff --git a/components/viz/common/gpu/vulkan_in_process_context_provider.h b/components/viz/common/gpu/vulkan_in_process_context_provider.h
index 9522620..a906f8f 100644
--- a/components/viz/common/gpu/vulkan_in_process_context_provider.h
+++ b/components/viz/common/gpu/vulkan_in_process_context_provider.h
@@ -27,6 +27,7 @@
   static scoped_refptr<VulkanInProcessContextProvider> Create(
       gpu::VulkanImplementation* vulkan_implementation);
 
+  bool Initialize();
   void Destroy();
 
   // VulkanContextProvider implementation
@@ -38,13 +39,12 @@
       std::vector<VkSemaphore> semaphores) override;
   void EnqueueSecondaryCBPostSubmitTask(base::OnceClosure closure) override;
 
- private:
+ protected:
   explicit VulkanInProcessContextProvider(
       gpu::VulkanImplementation* vulkan_implementation);
   ~VulkanInProcessContextProvider() override;
 
-  bool Initialize();
-
+ private:
 #if BUILDFLAG(ENABLE_VULKAN)
   sk_sp<GrContext> gr_context_;
   gpu::VulkanImplementation* vulkan_implementation_;
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index 85d79c8..2260e347 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -974,9 +974,12 @@
 #endif
   }
 
-  if (should_start_service_manager_only)
+  if (should_start_service_manager_only) {
+    DVLOG(0) << "Chrome is running in ServiceManager only mode.";
     return -1;
+  }
 
+  DVLOG(0) << "Chrome is running in full browser mode.";
   is_browser_main_loop_started_ = true;
   startup_data_ = std::make_unique<StartupDataImpl>();
   startup_data_->thread = std::move(service_manager_thread_);
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 25b644c..66bdd842 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -16,6 +16,7 @@
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
 
 using testing::Each;
 using testing::Not;
@@ -404,4 +405,21 @@
   EXPECT_FALSE(b2_observer.deleted());
 }
 
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DisallowedFeatureOnPage) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // Navigate to a page that has an unsupported feature for bfcache.
+  NavigateToURL(
+      shell(),
+      embedded_test_server()->GetURL(
+          "a.com", "/back_forward_cache/page_with_dedicated_worker.html"));
+  RenderFrameDeletedObserver delete_rfh_a(current_frame_host());
+
+  // Navigate away.
+  NavigateToURL(shell(),
+                embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // The page with the unsupported feature should be deleted (not cached).
+  delete_rfh_a.WaitUntilDeleted();
+}
 }  // namespace content
diff --git a/content/browser/devtools/protocol/system_info_handler.cc b/content/browser/devtools/protocol/system_info_handler.cc
index b6030a1..4fcc026a 100644
--- a/content/browser/devtools/protocol/system_info_handler.cc
+++ b/content/browser/devtools/protocol/system_info_handler.cc
@@ -5,6 +5,7 @@
 #include "content/browser/devtools/protocol/system_info_handler.h"
 
 #include <stdint.h>
+
 #include <utility>
 
 #include "base/bind.h"
@@ -37,6 +38,13 @@
 using SystemInfo::GPUInfo;
 using GetInfoCallback = SystemInfo::Backend::GetInfoCallback;
 
+std::unique_ptr<SystemInfo::Size> GfxSizeToSystemInfoSize(
+    const gfx::Size& size) {
+  return SystemInfo::Size::Create()
+      .SetWidth(size.width())
+      .SetHeight(size.height())
+      .Build();
+}
 // Give the GPU process a few seconds to provide GPU info.
 // Linux Debug builds need more time -- see Issue 796437.
 // Windows builds need more time -- see Issue 873112.
@@ -126,6 +134,57 @@
                             .Build();
 }
 
+std::unique_ptr<SystemInfo::VideoDecodeAcceleratorCapability>
+VideoDecodeAcceleratorSupportedProfileToProtocol(
+    const gpu::VideoDecodeAcceleratorSupportedProfile& profile) {
+  return SystemInfo::VideoDecodeAcceleratorCapability::Create()
+      .SetProfile(media::GetProfileName(
+          static_cast<media::VideoCodecProfile>(profile.profile)))
+      .SetMaxResolution(GfxSizeToSystemInfoSize(profile.max_resolution))
+      .SetMinResolution(GfxSizeToSystemInfoSize(profile.min_resolution))
+      .Build();
+}
+
+std::unique_ptr<SystemInfo::VideoEncodeAcceleratorCapability>
+VideoEncodeAcceleratorSupportedProfileToProtocol(
+    const gpu::VideoEncodeAcceleratorSupportedProfile& profile) {
+  return SystemInfo::VideoEncodeAcceleratorCapability::Create()
+      .SetProfile(media::GetProfileName(
+          static_cast<media::VideoCodecProfile>(profile.profile)))
+      .SetMaxResolution(GfxSizeToSystemInfoSize(profile.max_resolution))
+      .SetMaxFramerateNumerator(profile.max_framerate_numerator)
+      .SetMaxFramerateDenominator(profile.max_framerate_denominator)
+      .Build();
+}
+
+std::unique_ptr<SystemInfo::ImageDecodeAcceleratorCapability>
+ImageDecodeAcceleratorSupportedProfileToProtocol(
+    const gpu::ImageDecodeAcceleratorSupportedProfile& profile) {
+  std::unique_ptr<protocol::Array<std::string>> subsamplings;
+  for (const auto subsampling : profile.subsamplings) {
+    switch (subsampling) {
+      case gpu::ImageDecodeAcceleratorSubsampling::k420:
+        subsamplings->addItem(SystemInfo::SubsamplingFormatEnum::Yuv420);
+        break;
+      case gpu::ImageDecodeAcceleratorSubsampling::k422:
+        subsamplings->addItem(SystemInfo::SubsamplingFormatEnum::Yuv422);
+        break;
+      case gpu::ImageDecodeAcceleratorSubsampling::k444:
+        subsamplings->addItem(SystemInfo::SubsamplingFormatEnum::Yuv444);
+        break;
+    }
+  }
+
+  return SystemInfo::ImageDecodeAcceleratorCapability::Create()
+      .SetImageType(profile.image_type == gpu::ImageDecodeAcceleratorType::kJpeg
+                        ? "JPEG"
+                        : "Unknown")
+      .SetMaxDimensions(GfxSizeToSystemInfoSize(profile.max_encoded_dimensions))
+      .SetMinDimensions(GfxSizeToSystemInfoSize(profile.min_encoded_dimensions))
+      .SetSubsamplings(std::move(subsamplings))
+      .Build();
+}
+
 void SendGetInfoResponse(std::unique_ptr<GetInfoCallback> callback) {
   gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
   std::unique_ptr<protocol::Array<GPUDevice>> devices =
@@ -153,12 +212,40 @@
   for (const std::string& s : GetDriverBugWorkarounds())
       driver_bug_workarounds->addItem(s);
 
-  std::unique_ptr<GPUInfo> gpu = GPUInfo::Create()
-      .SetDevices(std::move(devices))
-      .SetAuxAttributes(std::move(aux_attributes))
-      .SetFeatureStatus(std::move(feature_status))
-      .SetDriverBugWorkarounds(std::move(driver_bug_workarounds))
-      .Build();
+  auto decoding_profiles =
+      protocol::Array<SystemInfo::VideoDecodeAcceleratorCapability>::create();
+  for (const auto& profile :
+       gpu_info.video_decode_accelerator_capabilities.supported_profiles) {
+    decoding_profiles->addItem(
+        VideoDecodeAcceleratorSupportedProfileToProtocol(profile));
+  }
+
+  auto encoding_profiles =
+      protocol::Array<SystemInfo::VideoEncodeAcceleratorCapability>::create();
+  for (const auto& profile :
+       gpu_info.video_encode_accelerator_supported_profiles) {
+    encoding_profiles->addItem(
+        VideoEncodeAcceleratorSupportedProfileToProtocol(profile));
+  }
+
+  auto image_profiles =
+      protocol::Array<SystemInfo::ImageDecodeAcceleratorCapability>::create();
+  for (const auto& profile :
+       gpu_info.image_decode_accelerator_supported_profiles) {
+    image_profiles->addItem(
+        ImageDecodeAcceleratorSupportedProfileToProtocol(profile));
+  }
+
+  std::unique_ptr<GPUInfo> gpu =
+      GPUInfo::Create()
+          .SetDevices(std::move(devices))
+          .SetAuxAttributes(std::move(aux_attributes))
+          .SetFeatureStatus(std::move(feature_status))
+          .SetDriverBugWorkarounds(std::move(driver_bug_workarounds))
+          .SetVideoDecoding(std::move(decoding_profiles))
+          .SetVideoEncoding(std::move(encoding_profiles))
+          .SetImageDecoding(std::move(image_profiles))
+          .Build();
 
   base::CommandLine* command = base::CommandLine::ForCurrentProcess();
 #if defined(OS_WIN)
diff --git a/content/browser/font_unique_name_lookup/font_unique_name_lookup.cc b/content/browser/font_unique_name_lookup/font_unique_name_lookup.cc
index 3c6c3075..6bfbf36f 100644
--- a/content/browser/font_unique_name_lookup/font_unique_name_lookup.cc
+++ b/content/browser/font_unique_name_lookup/font_unique_name_lookup.cc
@@ -9,13 +9,16 @@
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "base/time/time.h"
+#include "third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h"
 #include "third_party/blink/public/common/font_unique_name_lookup/font_unique_name_table.pb.h"
 #include "third_party/blink/public/common/font_unique_name_lookup/icu_fold_case_util.h"
 
-#include <algorithm>
 #include <set>
 #include <vector>
 #include "third_party/icu/source/common/unicode/unistr.h"
@@ -28,6 +31,42 @@
 static const char* const kAndroidFontPaths[] = {"/system/fonts",
                                                 "/vendor/fonts"};
 
+// These values are logged to UMA. Entries should not be renumbered and
+// numeric values should never be reused. Please keep in sync with
+// "FontScanningResult" in src/tools/metrics/histograms/enums.xml.
+enum class FontScanningResult {
+  kSuccess = 0,
+  kFtNewFaceFailed = 1,
+  kZeroNameTableEntries = 2,
+  kUnableToRetriveNameEntry = 3,
+  kNameInvalidUnicode = 4,
+  kMaxValue = kNameInvalidUnicode
+};
+
+void LogUMAFontScanningResult(FontScanningResult result) {
+  UMA_HISTOGRAM_ENUMERATION("Blink.Fonts.AndroidFontScanningResult", result);
+}
+
+void LogUMAPersistSuccess(bool success) {
+  UMA_HISTOGRAM_BOOLEAN("Blink.Fonts.AndroidFontScanningPersistToFileSuccess",
+                        success);
+}
+
+void LogUMALoadFromFileSuccess(bool success) {
+  UMA_HISTOGRAM_BOOLEAN("Blink.Fonts.AndroidFontScanningLoadFromFileSuccess",
+                        success);
+}
+
+void LogUMAFontScanningUpdateNeeded(bool update_needed) {
+  UMA_HISTOGRAM_BOOLEAN("Blink.Fonts.AndroidFontScanningUpdateNeeded",
+                        update_needed);
+}
+
+void LogUMAFontScanningDuration(base::TimeDelta duration) {
+  UMA_HISTOGRAM_MEDIUM_TIMES("Blink.Fonts.AndroidFontScanningTableBuildTime",
+                             duration);
+}
+
 bool SfntNameIsEnglish(const FT_SfntName& sfnt_name) {
   if (sfnt_name.platform_id == TT_PLATFORM_MICROSOFT)
     return sfnt_name.language_id == TT_MS_LANGID_ENGLISH_UNITED_STATES;
@@ -36,6 +75,20 @@
   return false;
 }
 
+// Scoped wrapper for a FreeType library object in order to ensure
+// initialization and tear down. Used during scanning font files.
+class ScopedFtLibrary {
+ public:
+  ScopedFtLibrary() { FT_Init_FreeType(&ft_library_); }
+
+  ~ScopedFtLibrary() { FT_Done_FreeType(ft_library_); }
+
+  FT_Library get() { return ft_library_; }
+
+ private:
+  FT_Library ft_library_;
+};
+
 // Convenience scoped wrapper for FT_Face instances. Takes care of handling
 // FreeType memory by calling FT_Done_Face on destruction.
 class ScopedFtFace {
@@ -72,191 +125,18 @@
   FT_Error ft_error_ = FT_Err_Ok;
 };
 
-}  // namespace
-
-namespace content {
-
-class PlatformFontUniqueNameLookup : public FontUniqueNameLookup {
- public:
-  PlatformFontUniqueNameLookup() : FontUniqueNameLookup(GetCacheDirectory()) {
-    // Error from LoadFromFile() is ignored: Loading the cache file could be
-    // recovered from by rebuilding the font table. UpdateTableIfNeeded() checks
-    // whether the internal base::MappedReadOnlyRegion has a size, which it
-    // doesn't if the LoadFromFile() failed. If it doesn't have a size, the
-    // table is rebuild by calling UpdateTable().
-    LoadFromFile();
-    if (UpdateTableIfNeeded()) {
-      // TODO(drott): Add UMA histograms for recording cache read and write
-      // failures.
-      PersistToFile();
-    }
-  }
-
- private:
-  static base::FilePath GetCacheDirectory() {
-    base::FilePath cache_directory;
-    base::PathService::Get(base::DIR_CACHE, &cache_directory);
-    return cache_directory;
-  }
-};
-
-FontUniqueNameLookup& FontUniqueNameLookup::GetInstance() {
-  static base::NoDestructor<PlatformFontUniqueNameLookup> sInstance;
-  return *sInstance.get();
-}
-
-FontUniqueNameLookup::FontUniqueNameLookup(FontUniqueNameLookup&&) = default;
-
-FontUniqueNameLookup::FontUniqueNameLookup(
-    const base::FilePath& cache_directory)
-    : cache_directory_(cache_directory) {
-  if (!DirectoryExists(cache_directory_) ||
-      !base::PathIsWritable(cache_directory_)) {
-    DCHECK(false) << "Error accessing cache directory for writing: "
-                  << cache_directory_.value();
-    cache_directory_ = base::FilePath();
-  }
-  FT_Init_FreeType(&ft_library_);
-}
-
-FontUniqueNameLookup::~FontUniqueNameLookup() {
-  FT_Done_FreeType(ft_library_);
-}
-
-base::ReadOnlySharedMemoryRegion
-FontUniqueNameLookup::GetUniqueNameTableAsSharedMemoryRegion() const {
-  return proto_storage_.region.Duplicate();
-}
-
-bool FontUniqueNameLookup::IsValid() {
-  return proto_storage_.IsValid() && proto_storage_.mapping.size();
-}
-
-bool FontUniqueNameLookup::UpdateTableIfNeeded() {
-  blink::FontUniqueNameTable font_table;
-  bool update_needed =
-      !proto_storage_.IsValid() || !proto_storage_.mapping.size() ||
-      !font_table.ParseFromArray(proto_storage_.mapping.memory(),
-                                 proto_storage_.mapping.size()) ||
-      font_table.stored_for_platform_version_identifier() !=
-          GetAndroidBuildFingerprint();
-  if (update_needed)
-    UpdateTable();
-  return update_needed;
-}
-
-bool FontUniqueNameLookup::UpdateTable() {
-  std::vector<std::string> font_files_to_index = GetFontFilePaths();
-
-  blink::FontUniqueNameTable font_table;
-  font_table.set_stored_for_platform_version_identifier(
-      GetAndroidBuildFingerprint());
-  for (const auto& font_file : font_files_to_index) {
-    int32_t number_of_faces = NumberOfFacesInFontFile(font_file);
-    for (int32_t i = 0; i < number_of_faces; ++i) {
-      IndexFile(&font_table, font_file, i);
-    }
-  }
-
-  proto_storage_ =
-      base::ReadOnlySharedMemoryRegion::Create(font_table.ByteSizeLong());
-  if (!IsValid())
-    return false;
-
-  if (!font_table.SerializeToArray(proto_storage_.mapping.memory(),
-                                   proto_storage_.mapping.size())) {
-    proto_storage_ = base::MappedReadOnlyRegion();
-    return false;
-  }
-  return true;
-}
-
-bool FontUniqueNameLookup::LoadFromFile() {
-  // Reset to empty to ensure IsValid() is false if reading fails.
-  proto_storage_ = base::MappedReadOnlyRegion();
-  base::File table_cache_file(
-      TableCacheFilePath(),
-      base::File::FLAG_OPEN | base::File::Flags::FLAG_READ);
-  if (!table_cache_file.IsValid())
-    return false;
-  proto_storage_ =
-      base::ReadOnlySharedMemoryRegion::Create(table_cache_file.GetLength());
-  if (!IsValid())
-    return false;
-  int read_result = table_cache_file.Read(
-      0, static_cast<char*>(proto_storage_.mapping.memory()),
-      table_cache_file.GetLength());
-  // If no bytes were read or Read() returned -1 we are not able to reconstruct
-  // a font table from the cached file.
-  if (read_result <= 0) {
-    proto_storage_ = base::MappedReadOnlyRegion();
-    return false;
-  }
-
-  blink::FontUniqueNameTable font_table;
-  if (!font_table.ParseFromArray(proto_storage_.mapping.memory(),
-                                 proto_storage_.mapping.size())) {
-    proto_storage_ = base::MappedReadOnlyRegion();
-    return false;
-  }
-
-  return true;
-}
-
-bool FontUniqueNameLookup::PersistToFile() {
-  DCHECK(IsValid());
-  if (!IsValid())
-    return false;
-  base::File table_cache_file(
-      TableCacheFilePath(),
-      base::File::FLAG_CREATE_ALWAYS | base::File::Flags::FLAG_WRITE);
-  if (!table_cache_file.IsValid())
-    return false;
-  if (table_cache_file.Write(
-          0, static_cast<char*>(proto_storage_.mapping.memory()),
-          proto_storage_.mapping.size()) == -1) {
-    table_cache_file.SetLength(0);
-    proto_storage_ = base::MappedReadOnlyRegion();
-    return false;
-  }
-  return true;
-}
-
-base::FilePath FontUniqueNameLookup::TableCacheFilePath() {
-  return base::FilePath(
-      cache_directory_.Append(base::FilePath(kProtobufFilename)));
-}
-
-void FontUniqueNameLookup::IndexFile(blink::FontUniqueNameTable* font_table,
-                                     const std::string& font_file_path,
-                                     uint32_t ttc_index) {
-  ScopedFtFace face(ft_library_, font_file_path.c_str(), ttc_index);
+void IndexFile(FT_Library ft_library,
+               blink::FontUniqueNameTable* font_table,
+               const std::string& font_file_path,
+               uint32_t ttc_index) {
+  ScopedFtFace face(ft_library, font_file_path.c_str(), ttc_index);
   if (!face.IsValid()) {
-    // TODO(drott): Track font file scanning failures in UMA.
-    LOG(ERROR) << "Unable to open font file for indexing: "
-               << font_file_path.c_str()
-               << " - FreeType FT_Error code: " << face.error();
+    LogUMAFontScanningResult(FontScanningResult::kFtNewFaceFailed);
     return;
   }
 
   if (!FT_Get_Sfnt_Name_Count(face.get())) {
-    LOG(ERROR) << "Zero name table entries in font file: "
-               << font_file_path.c_str();
-    return;
-  }
-
-  // Get file attributes
-  base::File font_file_for_info(
-      base::FilePath(font_file_path.c_str()),
-      base::File::FLAG_OPEN | base::File::Flags::FLAG_READ);
-  if (!font_file_for_info.IsValid()) {
-    LOG(ERROR) << "Unable to open font file: " << font_file_path.c_str();
-    return;
-  }
-  base::File::Info font_file_info;
-  if (!font_file_for_info.GetInfo(&font_file_info)) {
-    LOG(ERROR) << "Unable to get font file attributes for: "
-               << font_file_path.c_str();
+    LogUMAFontScanningResult(FontScanningResult::kZeroNameTableEntries);
     return;
   }
 
@@ -270,11 +150,18 @@
   for (size_t i = 0; i < FT_Get_Sfnt_Name_Count(face.get()); ++i) {
     FT_SfntName sfnt_name;
     if (FT_Get_Sfnt_Name(face.get(), i, &sfnt_name) != 0) {
-      LOG(ERROR) << "Unable to retrieve Sfnt Name table for font file: "
-                 << font_file_path.c_str();
+      LogUMAFontScanningResult(FontScanningResult::kUnableToRetriveNameEntry);
       return;
     }
 
+    // From the CSS Fonts spec chapter 4.3. Font reference: the src descriptor
+    // "For OpenType fonts with multiple localizations of the full font name,
+    // the US English version is used (language ID = 0x409 for Windows and
+    // language ID = 0 for Macintosh) or the first localization when a US
+    // English full font name is not available (the OpenType specification
+    // recommends that all fonts minimally include US English names)."
+    // Since we can assume Android system fonts contain an English name,
+    // continue here.
     if (!SfntNameIsEnglish(sfnt_name))
       continue;
 
@@ -291,8 +178,10 @@
     icu::UnicodeString sfnt_name_unicode(
         reinterpret_cast<char*>(sfnt_name.string), sfnt_name.string_len,
         codepage_name.c_str());
-    if (sfnt_name_unicode.isBogus())
+    if (sfnt_name_unicode.isBogus()) {
+      LogUMAFontScanningResult(FontScanningResult::kNameInvalidUnicode);
       return;
+    }
     // Firefox performs case insensitive matching for src: local().
     sfnt_name_unicode.foldCase();
     sfnt_name_unicode.toUTF8String(sfnt_name_string);
@@ -302,28 +191,213 @@
     name_mapping->set_font_name(blink::IcuFoldCase(sfnt_name_string));
     name_mapping->set_font_index(added_font_index);
   }
-
-  // Sort names and update protobuf, essential for binary search in matching to
-  // work.
-  std::sort(font_table->mutable_name_map()->begin(),
-            font_table->mutable_name_map()->end(),
-            [](const blink::FontUniqueNameTable_UniqueNameToFontMapping& a,
-               const blink::FontUniqueNameTable_UniqueNameToFontMapping& b) {
-              return a.font_name() < b.font_name();
-            });
+  LogUMAFontScanningResult(FontScanningResult::kSuccess);
 }
 
-int32_t FontUniqueNameLookup::NumberOfFacesInFontFile(
-    const std::string& font_filename) const {
+int32_t NumberOfFacesInFontFile(FT_Library ft_library,
+                                const std::string& font_filename) {
   // According to FreeType documentation calling FT_Open_Face with a negative
   // index value allows us to probe how many fonts can be found in a font file
-  // (which can be a single font ttf or a TrueType collection (.ttc).
-  ScopedFtFace probe_face(ft_library_, font_filename.c_str(), -1);
+  // (which can be a single font ttf or a TrueType collection (.ttc)).
+  ScopedFtFace probe_face(ft_library, font_filename.c_str(), -1);
   if (!probe_face.IsValid())
     return 0;
   return probe_face.get()->num_faces;
 }
 
+}  // namespace
+
+namespace content {
+
+class PlatformFontUniqueNameLookup : public FontUniqueNameLookup {
+ public:
+  PlatformFontUniqueNameLookup() : FontUniqueNameLookup(GetCacheDirectory()) {
+    ScheduleLoadOrUpdateTable();
+  }
+
+ private:
+  static base::FilePath GetCacheDirectory() {
+    base::FilePath cache_directory;
+    base::PathService::Get(base::DIR_CACHE, &cache_directory);
+    return cache_directory;
+  }
+};
+
+FontUniqueNameLookup& FontUniqueNameLookup::GetInstance() {
+  static base::NoDestructor<PlatformFontUniqueNameLookup> sInstance;
+  return *sInstance.get();
+}
+
+FontUniqueNameLookup::FontUniqueNameLookup(
+    const base::FilePath& cache_directory)
+    : cache_directory_(cache_directory) {
+  if (!DirectoryExists(cache_directory_) ||
+      !base::PathIsWritable(cache_directory_)) {
+    DCHECK(false) << "Error accessing cache directory for writing: "
+                  << cache_directory_.value();
+    cache_directory_ = base::FilePath();
+  }
+}
+
+FontUniqueNameLookup::~FontUniqueNameLookup() = default;
+
+base::ReadOnlySharedMemoryRegion FontUniqueNameLookup::DuplicateMemoryRegion() {
+  DCHECK(proto_storage_.IsValid() && proto_storage_.mapping.size());
+  return proto_storage_.region.Duplicate();
+}
+
+void FontUniqueNameLookup::QueueShareMemoryRegionWhenReady(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    blink::mojom::FontUniqueNameLookup::GetUniqueNameLookupTableCallback
+        callback) {
+  pending_callbacks_.emplace_back(std::move(task_runner), std::move(callback));
+}
+
+bool FontUniqueNameLookup::IsValid() {
+  return proto_storage_ready_.IsSignaled() && proto_storage_.IsValid() &&
+         proto_storage_.mapping.size();
+}
+
+bool FontUniqueNameLookup::UpdateTableIfNeeded() {
+  blink::FontUniqueNameTable font_table;
+  bool update_needed =
+      !proto_storage_.IsValid() || !proto_storage_.mapping.size() ||
+      !font_table.ParseFromArray(proto_storage_.mapping.memory(),
+                                 proto_storage_.mapping.size()) ||
+      font_table.stored_for_platform_version_identifier() !=
+          GetAndroidBuildFingerprint();
+
+  LogUMAFontScanningUpdateNeeded(update_needed);
+  if (update_needed)
+    UpdateTable();
+  return update_needed;
+}
+
+bool FontUniqueNameLookup::UpdateTable() {
+  base::TimeTicks update_table_start_time = base::TimeTicks::Now();
+
+  std::vector<std::string> font_files_to_index = GetFontFilePaths();
+
+  ScopedFtLibrary ft_library;
+  blink::FontUniqueNameTable font_table;
+  font_table.set_stored_for_platform_version_identifier(
+      GetAndroidBuildFingerprint());
+  for (const auto& font_file : font_files_to_index) {
+    int32_t number_of_faces =
+        NumberOfFacesInFontFile(ft_library.get(), font_file);
+    for (int32_t i = 0; i < number_of_faces; ++i) {
+      IndexFile(ft_library.get(), &font_table, font_file, i);
+    }
+  }
+
+  blink::FontTableMatcher::SortUniqueNameTableForSearch(&font_table);
+
+  proto_storage_ =
+      base::ReadOnlySharedMemoryRegion::Create(font_table.ByteSizeLong());
+  if (!proto_storage_.IsValid() || !proto_storage_.mapping.size())
+    return false;
+
+  if (!font_table.SerializeToArray(proto_storage_.mapping.memory(),
+                                   proto_storage_.mapping.size())) {
+    proto_storage_ = base::MappedReadOnlyRegion();
+    return false;
+  }
+
+  base::TimeDelta duration = base::TimeTicks::Now() - update_table_start_time;
+  LogUMAFontScanningDuration(duration);
+
+  return true;
+}
+
+bool FontUniqueNameLookup::LoadFromFile() {
+  // Reset to empty to ensure IsValid() is false if reading fails.
+  proto_storage_ = base::MappedReadOnlyRegion();
+  base::File table_cache_file(
+      TableCacheFilePath(),
+      base::File::FLAG_OPEN | base::File::Flags::FLAG_READ);
+  if (!table_cache_file.IsValid()) {
+    LogUMALoadFromFileSuccess(false);
+    return false;
+  }
+  proto_storage_ =
+      base::ReadOnlySharedMemoryRegion::Create(table_cache_file.GetLength());
+  if (!proto_storage_.IsValid() || !proto_storage_.mapping.size()) {
+    LogUMALoadFromFileSuccess(false);
+    return false;
+  }
+  int read_result = table_cache_file.Read(
+      0, static_cast<char*>(proto_storage_.mapping.memory()),
+      table_cache_file.GetLength());
+  // If no bytes were read or Read() returned -1 we are not able to reconstruct
+  // a font table from the cached file.
+  if (read_result <= 0) {
+    proto_storage_ = base::MappedReadOnlyRegion();
+    LogUMALoadFromFileSuccess(false);
+    return false;
+  }
+
+  blink::FontUniqueNameTable font_table;
+  if (!font_table.ParseFromArray(proto_storage_.mapping.memory(),
+                                 proto_storage_.mapping.size())) {
+    proto_storage_ = base::MappedReadOnlyRegion();
+    LogUMALoadFromFileSuccess(false);
+    return false;
+  }
+  LogUMALoadFromFileSuccess(true);
+  return true;
+}
+
+bool FontUniqueNameLookup::PersistToFile() {
+  DCHECK(proto_storage_.IsValid() && proto_storage_.mapping.size());
+  base::File table_cache_file(
+      TableCacheFilePath(),
+      base::File::FLAG_CREATE_ALWAYS | base::File::Flags::FLAG_WRITE);
+  if (!table_cache_file.IsValid()) {
+    LogUMAPersistSuccess(false);
+    return false;
+  }
+  if (table_cache_file.Write(
+          0, static_cast<char*>(proto_storage_.mapping.memory()),
+          proto_storage_.mapping.size()) == -1) {
+    table_cache_file.SetLength(0);
+    proto_storage_ = base::MappedReadOnlyRegion();
+    LogUMAPersistSuccess(false);
+    return false;
+  }
+  LogUMAPersistSuccess(true);
+  return true;
+}
+
+void FontUniqueNameLookup::ScheduleLoadOrUpdateTable() {
+  base::PostTaskWithTraits(FROM_HERE,
+                           {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+                            base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+                           base::BindOnce(
+                               [](FontUniqueNameLookup* instance) {
+                                 // Error from LoadFromFile() is ignored:
+                                 // Loading the cache file could be recovered
+                                 // from by rebuilding the font table.
+                                 // UpdateTableIfNeeded() checks whether the
+                                 // internal base::MappedReadOnlyRegion has a
+                                 // size, which it doesn't if the LoadFromFile()
+                                 // failed. If it doesn't have a size, the table
+                                 // is rebuild by calling UpdateTable().
+
+                                 instance->LoadFromFile();
+                                 if (instance->UpdateTableIfNeeded()) {
+                                   instance->PersistToFile();
+                                 }
+                                 instance->proto_storage_ready_.Signal();
+                                 instance->PostCallbacks();
+                               },
+                               base::Unretained(this)));
+}
+
+base::FilePath FontUniqueNameLookup::TableCacheFilePath() {
+  return base::FilePath(
+      cache_directory_.Append(base::FilePath(kProtobufFilename)));
+}
+
 std::string FontUniqueNameLookup::GetAndroidBuildFingerprint() const {
   return android_build_fingerprint_for_testing_.size()
              ? android_build_fingerprint_for_testing_
@@ -349,4 +423,30 @@
   return font_files;
 }
 
+FontUniqueNameLookup::CallbackOnTaskRunner::CallbackOnTaskRunner(
+    scoped_refptr<base::SequencedTaskRunner> runner,
+    blink::mojom::FontUniqueNameLookup::GetUniqueNameLookupTableCallback
+        callback)
+    : task_runner(std::move(runner)), mojo_callback(std::move(callback)) {}
+
+FontUniqueNameLookup::CallbackOnTaskRunner::CallbackOnTaskRunner(
+    CallbackOnTaskRunner&& other) {
+  task_runner = std::move(other.task_runner);
+  mojo_callback = std::move(other.mojo_callback);
+  other.task_runner = nullptr;
+  other.mojo_callback =
+      blink::mojom::FontUniqueNameLookup::GetUniqueNameLookupTableCallback();
+}
+
+FontUniqueNameLookup::CallbackOnTaskRunner::~CallbackOnTaskRunner() = default;
+
+void FontUniqueNameLookup::PostCallbacks() {
+  for (auto& pending_callback : pending_callbacks_) {
+    pending_callback.task_runner->PostTask(
+        FROM_HERE, base::BindOnce(std::move(pending_callback.mojo_callback),
+                                  DuplicateMemoryRegion()));
+  }
+  pending_callbacks_.clear();
+}
+
 }  // namespace content
diff --git a/content/browser/font_unique_name_lookup/font_unique_name_lookup.h b/content/browser/font_unique_name_lookup/font_unique_name_lookup.h
index d76b635..1da05be 100644
--- a/content/browser/font_unique_name_lookup/font_unique_name_lookup.h
+++ b/content/browser/font_unique_name_lookup/font_unique_name_lookup.h
@@ -7,7 +7,9 @@
 
 #include "base/files/file_path.h"
 #include "base/memory/read_only_shared_memory_region.h"
+#include "base/sequenced_task_runner.h"
 #include "content/common/content_export.h"
+#include "third_party/blink/public/mojom/font_unique_name_lookup/font_unique_name_lookup.mojom.h"
 
 #include <ft2build.h>
 #include FT_SYSTEM_H
@@ -16,10 +18,6 @@
 
 #include <string>
 
-namespace blink {
-class FontUniqueNameTable;
-}
-
 namespace content {
 
 // Scans a set of font files for the full font name and postscript name
@@ -46,15 +44,14 @@
   FontUniqueNameLookup(const base::FilePath& cache_directory);
   ~FontUniqueNameLookup();
 
-  // Default move contructor.
-  FontUniqueNameLookup(FontUniqueNameLookup&&);
-  // Default move assigment operator.
-  FontUniqueNameLookup& operator=(FontUniqueNameLookup&&) = default;
-
   // Return a ReadOnlySharedMemoryRegion to access the serialized form of the
   // current lookup table. To be used with FontTableMatcher.
-  base::ReadOnlySharedMemoryRegion GetUniqueNameTableAsSharedMemoryRegion()
-      const;
+  base::ReadOnlySharedMemoryRegion DuplicateMemoryRegion();
+
+  void QueueShareMemoryRegionWhenReady(
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
+      blink::mojom::FontUniqueNameLookup::GetUniqueNameLookupTableCallback
+          callback);
 
   // Returns true if an up-to-date, consistent font table is present.
   bool IsValid();
@@ -99,16 +96,10 @@
   // Returns the storage location of the table cache protobuf file.
   base::FilePath TableCacheFilePathForTesting() { return TableCacheFilePath(); }
 
+ protected:
+  void ScheduleLoadOrUpdateTable();
+
  private:
-  // Scan the font file at |font_file_path| and given |ttc_index| and extract
-  // full font name and postscript name from the font and store it into the
-  // font_index_entry protobuf object.
-  void IndexFile(blink::FontUniqueNameTable* font_table,
-                 const std::string& font_file_path,
-                 uint32_t ttc_index);
-  // For a TrueType font collection, determine how many font faces are
-  // available in a file.
-  int32_t NumberOfFacesInFontFile(const std::string& font_filename) const;
 
   // If an Android build fingerprint override is set through
   // SetAndroidBuildFingerprint() return that, otherwise return the actual
@@ -122,13 +113,35 @@
 
   base::FilePath TableCacheFilePath();
 
-  base::FilePath cache_directory_;
-  FT_Library ft_library_;
+  void PostCallbacks();
+
+  // We have a asynchronous update tasks which need write access to the
+  // proto_storage_ MappedReadOnlyRegion after reading the index file from disk,
+  // or after scanning and indexing metadata from font files. At the same time,
+  // we may receive incoming Mojo requests to tell whether the proto_storage_
+  // storage area is already ready early for sync access by the
+  // renderers. Synchronize the information on whether the proto_storage_ is
+  // ready by means of a WaitableEvent.
+  base::WaitableEvent proto_storage_ready_;
   base::MappedReadOnlyRegion proto_storage_;
 
+  base::FilePath cache_directory_;
   std::string android_build_fingerprint_for_testing_ = "";
   std::vector<std::string> font_file_paths_for_testing_ =
       std::vector<std::string>();
+
+  struct CallbackOnTaskRunner {
+    CallbackOnTaskRunner(
+        scoped_refptr<base::SequencedTaskRunner>,
+        blink::mojom::FontUniqueNameLookup::GetUniqueNameLookupTableCallback);
+    CallbackOnTaskRunner(CallbackOnTaskRunner&&);
+    ~CallbackOnTaskRunner();
+    scoped_refptr<base::SequencedTaskRunner> task_runner;
+    blink::mojom::FontUniqueNameLookup::GetUniqueNameLookupTableCallback
+        mojo_callback;
+  };
+
+  std::vector<CallbackOnTaskRunner> pending_callbacks_;
 };
 }  // namespace content
 
diff --git a/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.cc b/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.cc
index bd0d45d..be58b95 100644
--- a/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.cc
+++ b/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.cc
@@ -12,6 +12,7 @@
 #include "base/task/post_task.h"
 #include "content/browser/font_unique_name_lookup/font_unique_name_lookup.h"
 #include "content/public/common/content_features.h"
+#include "mojo/public/cpp/bindings/callback_helpers.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 
 namespace content {
@@ -43,8 +44,27 @@
 void FontUniqueNameLookupService::GetUniqueNameLookupTable(
     GetUniqueNameLookupTableCallback callback) {
   DCHECK(GetTaskRunner()->RunsTasksInCurrentSequence());
-  std::move(callback).Run(
-      font_unique_name_lookup_.GetUniqueNameTableAsSharedMemoryRegion());
+  if (font_unique_name_lookup_.IsValid()) {
+    std::move(callback).Run(font_unique_name_lookup_.DuplicateMemoryRegion());
+  } else {
+    font_unique_name_lookup_.QueueShareMemoryRegionWhenReady(
+        GetTaskRunner(), std::move(callback));
+  }
+}
+
+void FontUniqueNameLookupService::GetUniqueNameLookupTableIfAvailable(
+    GetUniqueNameLookupTableIfAvailableCallback callback) {
+  DCHECK(GetTaskRunner()->RunsTasksInCurrentSequence());
+
+  base::ReadOnlySharedMemoryRegion invalid_region;
+  callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
+      std::move(callback), false, std::move(invalid_region));
+
+  if (!font_unique_name_lookup_.IsValid())
+    return;
+
+  std::move(callback).Run(true,
+                          font_unique_name_lookup_.DuplicateMemoryRegion());
 }
 
 }  // namespace content
diff --git a/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h b/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h
index f60ca495..228fc2c 100644
--- a/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h
+++ b/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h
@@ -26,6 +26,9 @@
   void GetUniqueNameLookupTable(
       GetUniqueNameLookupTableCallback callback) override;
 
+  void GetUniqueNameLookupTableIfAvailable(
+      GetUniqueNameLookupTableIfAvailableCallback callback) override;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(FontUniqueNameLookupService);
   ::content::FontUniqueNameLookup& font_unique_name_lookup_;
diff --git a/content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest.cc b/content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest.cc
index 7679118..3945b0d0 100644
--- a/content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest.cc
+++ b/content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest.cc
@@ -88,13 +88,13 @@
 TEST_F(FontUniqueNameLookupTest, TestBuildLookup) {
   ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
   base::ReadOnlySharedMemoryMapping mapping =
-      font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map();
+      font_unique_name_lookup_->DuplicateMemoryRegion().Map();
   blink::FontTableMatcher matcher(mapping);
   ASSERT_GT(matcher.AvailableFonts(), 0u);
   ASSERT_TRUE(font_unique_name_lookup_->PersistToFile());
   ASSERT_TRUE(font_unique_name_lookup_->LoadFromFile());
   blink::FontTableMatcher matcher_after_load(
-      font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+      font_unique_name_lookup_->DuplicateMemoryRegion().Map());
   ASSERT_GT(matcher_after_load.AvailableFonts(), 0u);
 }
 
@@ -108,30 +108,25 @@
   base::DeleteFile(font_unique_name_lookup_->TableCacheFilePathForTesting(),
                    false);
   ASSERT_FALSE(font_unique_name_lookup_->LoadFromFile());
-  ASSERT_FALSE(font_unique_name_lookup_->IsValid());
   ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
-  ASSERT_TRUE(font_unique_name_lookup_->IsValid());
   base::ReadOnlySharedMemoryMapping mapping =
-      font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map();
+      font_unique_name_lookup_->DuplicateMemoryRegion().Map();
   blink::FontTableMatcher matcher(mapping);
   ASSERT_GT(matcher.AvailableFonts(), 0u);
   ASSERT_TRUE(font_unique_name_lookup_->PersistToFile());
   ASSERT_TRUE(font_unique_name_lookup_->LoadFromFile());
-  ASSERT_TRUE(font_unique_name_lookup_->IsValid());
   TruncateFile(font_unique_name_lookup_->TableCacheFilePathForTesting(),
                TruncateLength::TruncateHalf);
   ASSERT_FALSE(font_unique_name_lookup_->LoadFromFile());
-  ASSERT_FALSE(font_unique_name_lookup_->IsValid());
   TruncateFile(font_unique_name_lookup_->TableCacheFilePathForTesting(),
                TruncateLength::TruncateToZero);
   ASSERT_FALSE(font_unique_name_lookup_->LoadFromFile());
-  ASSERT_FALSE(font_unique_name_lookup_->IsValid());
 }
 
 TEST_F(FontUniqueNameLookupTest, TestMatchPostScriptName) {
   ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
   blink::FontTableMatcher matcher(
-      font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+      font_unique_name_lookup_->DuplicateMemoryRegion().Map());
   ASSERT_GT(matcher.AvailableFonts(), 0u);
   auto match_result = matcher.MatchName(kRobotoCondensedBoldItalicNames[1]);
   ASSERT_TRUE(match_result);
@@ -152,7 +147,7 @@
   }
   ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
   blink::FontTableMatcher matcher(
-      font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+      font_unique_name_lookup_->DuplicateMemoryRegion().Map());
   std::vector<std::string> ttc_postscript_names = {
       "NotoSansCJKjp-Regular",     "NotoSansCJKkr-Regular",
       "NotoSansCJKsc-Regular",     "NotoSansCJKtc-Regular",
@@ -174,7 +169,7 @@
 TEST_F(FontUniqueNameLookupTest, TestMatchFullFontName) {
   ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
   blink::FontTableMatcher matcher(
-      font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+      font_unique_name_lookup_->DuplicateMemoryRegion().Map());
   auto match_result = matcher.MatchName(kRobotoCondensedBoldItalicNames[0]);
   ASSERT_TRUE(match_result);
   ASSERT_TRUE(EndsWith(match_result->font_path,
@@ -293,7 +288,7 @@
   font_file_corruptor_.ZeroAfterTableIndex();
   ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
   blink::FontTableMatcher matcher_after_update(
-      font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+      font_unique_name_lookup_->DuplicateMemoryRegion().Map());
   ASSERT_EQ(matcher_after_update.AvailableFonts(), 0u);
 }
 
@@ -301,7 +296,7 @@
   font_file_corruptor_.ZeroOutTableRecords();
   ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
   blink::FontTableMatcher matcher_after_update(
-      font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+      font_unique_name_lookup_->DuplicateMemoryRegion().Map());
   ASSERT_EQ(matcher_after_update.AvailableFonts(), 0u);
 }
 
@@ -323,7 +318,7 @@
 TEST_F(FontUniqueNameLookupUpdateTest, CompareSets) {
   ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
   blink::FontTableMatcher matcher_initial(
-      font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+      font_unique_name_lookup_->DuplicateMemoryRegion().Map());
   ASSERT_GT(matcher_initial.AvailableFonts(), 0u);
   font_unique_name_lookup_->SetFontFilePathsForTesting(
       SplitFontFilesList(AndroidFontFilesList(), true));
@@ -332,7 +327,7 @@
   font_unique_name_lookup_->SetAndroidBuildFingerprintForTesting("B");
   font_unique_name_lookup_->UpdateTableIfNeeded();
   blink::FontTableMatcher matcher_second_half(
-      font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+      font_unique_name_lookup_->DuplicateMemoryRegion().Map());
   ASSERT_GT(matcher_initial.AvailableFonts(), 0u);
   ASSERT_TRUE(matcher_initial.FontListIsDisjointFrom(matcher_second_half));
 }
diff --git a/content/browser/frame_host/back_forward_cache.cc b/content/browser/frame_host/back_forward_cache.cc
index 3c27c01..f55125e1 100644
--- a/content/browser/frame_host/back_forward_cache.cc
+++ b/content/browser/frame_host/back_forward_cache.cc
@@ -3,16 +3,47 @@
 // found in the LICENSE file.
 
 #include "content/browser/frame_host/back_forward_cache.h"
+
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/public/common/navigation_policy.h"
+#include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
 
 namespace content {
 
 namespace {
 
+using blink::scheduler::WebSchedulerTrackedFeature;
+
 // The number of document the BackForwardCache can hold per tab.
 static constexpr size_t kBackForwardCacheLimit = 3;
 
+// Converts a WebSchedulerTrackedFeature to a bit for use in a bitmask.
+constexpr uint64_t ToFeatureBit(WebSchedulerTrackedFeature feature) {
+  return 1 << static_cast<uint32_t>(feature);
+}
+
+// TODO(lowell): Finalize disallowed feature list, and test for each disallowed
+// feature.
+constexpr uint64_t kDisallowedFeatures =
+    ToFeatureBit(WebSchedulerTrackedFeature::kWebSocket) |
+    ToFeatureBit(WebSchedulerTrackedFeature::kWebRTC) |
+    ToFeatureBit(WebSchedulerTrackedFeature::kContainsPlugins) |
+    ToFeatureBit(WebSchedulerTrackedFeature::kDedicatedWorkerOrWorklet) |
+    ToFeatureBit(WebSchedulerTrackedFeature::kServiceWorkerControlledPage) |
+    ToFeatureBit(WebSchedulerTrackedFeature::kOutstandingIndexedDBTransaction) |
+    ToFeatureBit(
+        WebSchedulerTrackedFeature::kHasScriptableFramesInMultipleTabs) |
+    ToFeatureBit(WebSchedulerTrackedFeature::kRequestedGeolocationPermission) |
+    ToFeatureBit(
+        WebSchedulerTrackedFeature::kRequestedNotificationsPermission) |
+    ToFeatureBit(WebSchedulerTrackedFeature::kRequestedMIDIPermission) |
+    ToFeatureBit(WebSchedulerTrackedFeature::kRequestedAudioCapturePermission) |
+    ToFeatureBit(WebSchedulerTrackedFeature::kRequestedVideoCapturePermission) |
+    ToFeatureBit(WebSchedulerTrackedFeature::kRequestedSensorsPermission) |
+    ToFeatureBit(
+        WebSchedulerTrackedFeature::kRequestedBackgroundWorkPermission) |
+    ToFeatureBit(WebSchedulerTrackedFeature::kBroadcastChannel) |
+    ToFeatureBit(WebSchedulerTrackedFeature::kIndexedDBConnection);
 }  // namespace
 
 BackForwardCache::BackForwardCache() = default;
@@ -26,15 +57,13 @@
   if (!IsBackForwardCacheEnabled())
     return false;
 
-  // TODO(arthursonzogni): In a lot of other cases, a document must not be in
-  // the BackForwardCache. The main frame needs to be checked, but also its
-  // iframes.
-  // * Document using plugin.
-  // * Document not fully loaded.
-  // * Document with unload handlers.
-  // * Error pages.
-  // * AppCache?
-  // * ...
+  // Don't enable BackForwardCache if the page has any disallowed features.
+  // TODO(lowell): Handle races involving scheduler_tracked_features.
+  // One solution could be to listen for changes to scheduler_tracked_features
+  // and if we see a frame in bfcache starting to use something forbidden, evict
+  // it from the bfcache.
+  if (kDisallowedFeatures & rfh->scheduler_tracked_features())
+    return false;
 
   return true;
 }
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc
index 03a7930e..0dd95ed 100644
--- a/content/browser/frame_host/navigation_handle_impl.cc
+++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -360,6 +360,10 @@
   return navigation_request_->begin_params()->is_form_submission;
 }
 
+bool NavigationHandleImpl::WasInitiatedByLinkClick() {
+  return navigation_request_->begin_params()->was_initiated_by_link_click;
+}
+
 const std::string& NavigationHandleImpl::GetHrefTranslate() {
   return navigation_request_->common_params().href_translate;
 }
diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h
index 6a9bc1e..a6445b6 100644
--- a/content/browser/frame_host/navigation_handle_impl.h
+++ b/content/browser/frame_host/navigation_handle_impl.h
@@ -103,6 +103,7 @@
   const GlobalRequestID& GetGlobalRequestID() override;
   bool IsDownload() override;
   bool IsFormSubmission() override;
+  bool WasInitiatedByLinkClick() override;
   bool IsSignedExchangeInnerResponse() override;
   bool WasResponseCached() override;
   const net::ProxyServer& GetProxyServer() override;
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 14cc7e4c1..2171144 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -481,7 +481,7 @@
       extra_headers, net::LOAD_NORMAL, false /* skip_service_worker */,
       blink::mojom::RequestContextType::LOCATION,
       blink::WebMixedContentContextType::kBlockable, is_form_submission,
-      GURL() /* searchable_form_url */,
+      false /* was_initiated_by_link_click */, GURL() /* searchable_form_url */,
       std::string() /* searchable_form_encoding */,
       GURL() /* client_side_redirect_url */,
       base::nullopt /* devtools_initiator_info */);
diff --git a/content/browser/loader/navigation_url_loader_impl_unittest.cc b/content/browser/loader/navigation_url_loader_impl_unittest.cc
index e8d3b0a..23b754f4 100644
--- a/content/browser/loader/navigation_url_loader_impl_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_impl_unittest.cc
@@ -171,7 +171,9 @@
             headers, net::LOAD_NORMAL, false /* skip_service_worker */,
             blink::mojom::RequestContextType::LOCATION,
             blink::WebMixedContentContextType::kBlockable,
-            false /* is_form_submission */, GURL() /* searchable_form_url */,
+            false /* is_form_submission */,
+            false /* was_initiated_by_link_click */,
+            GURL() /* searchable_form_url */,
             std::string() /* searchable_form_encoding */,
             GURL() /* client_side_redirect_url */,
             base::nullopt /* devtools_initiator_info */);
diff --git a/content/browser/loader/navigation_url_loader_unittest.cc b/content/browser/loader/navigation_url_loader_unittest.cc
index 0c85d1f..567eab4 100644
--- a/content/browser/loader/navigation_url_loader_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_unittest.cc
@@ -89,7 +89,9 @@
             false /* skip_service_worker */,
             blink::mojom::RequestContextType::LOCATION,
             blink::WebMixedContentContextType::kBlockable,
-            false /* is_form_submission */, GURL() /* searchable_form_url */,
+            false /* is_form_submission */,
+            false /* was_initiated_by_link_click */,
+            GURL() /* searchable_form_url */,
             std::string() /* searchable_form_encoding */,
             GURL() /* client_side_redirect_url */,
             base::nullopt /* devtools_initiator_info */);
diff --git a/content/browser/loader/prefetch_url_loader.cc b/content/browser/loader/prefetch_url_loader.cc
index 37bc9a8..b0e75f4 100644
--- a/content/browser/loader/prefetch_url_loader.cc
+++ b/content/browser/loader/prefetch_url_loader.cc
@@ -171,7 +171,8 @@
       signed_exchange_prefetch_handler_) {
     prefetched_signed_exchange_cache_adapter_->OnReceiveRedirect(
         redirect_info.new_url,
-        signed_exchange_prefetch_handler_->ComputeHeaderIntegrity());
+        signed_exchange_prefetch_handler_->ComputeHeaderIntegrity(),
+        signed_exchange_prefetch_handler_->GetSignatureExpireTime());
   }
 
   resource_request_.url = redirect_info.new_url;
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc
index 20988e2..ad80ccc8 100644
--- a/content/browser/loader/resource_dispatcher_host_unittest.cc
+++ b/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -828,7 +828,9 @@
             false /* skip_service_worker */,
             blink::mojom::RequestContextType::LOCATION,
             blink::WebMixedContentContextType::kBlockable,
-            false /* is_form_submission */, GURL() /* searchable_form_url */,
+            false /* is_form_submission */,
+            false /* was_initiated_by_link_click */,
+            GURL() /* searchable_form_url */,
             std::string() /* searchable_form_encoding */,
             GURL() /* client_side_redirect_url */,
             base::nullopt /* devtools_initiator_info */);
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 7f766e0..716a27c 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -677,7 +677,9 @@
           false /* skip_service_worker */,
           blink::mojom::RequestContextType::LOCATION,
           blink::WebMixedContentContextType::kBlockable,
-          false /* is_form_submission */, GURL() /* searchable_form_url */,
+          false /* is_form_submission */,
+          false /* was_initiated_by_link_click */,
+          GURL() /* searchable_form_url */,
           std::string() /* searchable_form_encoding */,
           GURL() /* client_side_redirect_url */,
           base::nullopt /* devtools_initiator_info */);
diff --git a/content/browser/portal/portal.cc b/content/browser/portal/portal.cc
index 5eee6ffa..98456b74 100644
--- a/content/browser/portal/portal.cc
+++ b/content/browser/portal/portal.cc
@@ -193,11 +193,8 @@
 
   WebContentsDelegate* delegate = outer_contents->GetDelegate();
   bool is_loading = portal_contents_impl_->IsLoading();
-  FrameTreeNode* outer_frame_tree_node = FrameTreeNode::GloballyFindByID(
-      portal_contents_impl_->GetOuterDelegateFrameTreeNodeId());
   std::unique_ptr<WebContents> portal_contents =
       portal_contents_impl_->DetachFromOuterWebContents();
-  owner_render_frame_host_->RemoveChild(outer_frame_tree_node);
 
   auto* outer_contents_main_frame_view = static_cast<RenderWidgetHostViewBase*>(
       outer_contents->GetMainFrame()->GetView());
diff --git a/content/browser/portal/portal_browsertest.cc b/content/browser/portal/portal_browsertest.cc
index 3d903f32..88743034 100644
--- a/content/browser/portal/portal_browsertest.cc
+++ b/content/browser/portal/portal_browsertest.cc
@@ -584,45 +584,6 @@
   input_event_ack_waiter.Wait();
 }
 
-// Tests that the outer FrameTreeNode is deleted after activation.
-IN_PROC_BROWSER_TEST_F(PortalBrowserTest, FrameDeletedAfterActivation) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), embedded_test_server()->GetURL("portal.test", "/title1.html")));
-  WebContentsImpl* web_contents_impl =
-      static_cast<WebContentsImpl*>(shell()->web_contents());
-  RenderFrameHostImpl* main_frame = web_contents_impl->GetMainFrame();
-
-  Portal* portal = nullptr;
-  {
-    PortalCreatedObserver portal_created_observer(main_frame);
-    GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
-    EXPECT_TRUE(ExecJs(
-        main_frame, JsReplace("var portal = document.createElement('portal');"
-                              "portal.src = $1;"
-                              "document.body.appendChild(portal);",
-                              a_url)));
-    portal = portal_created_observer.WaitUntilPortalCreated();
-  }
-  WebContentsImpl* portal_contents = portal->GetPortalContents();
-
-  // The portal should not have navigated yet; wait for the first navigation.
-  TestNavigationObserver navigation_observer(portal_contents);
-  navigation_observer.Wait();
-
-  FrameTreeNode* outer_frame_tree_node = FrameTreeNode::GloballyFindByID(
-      portal_contents->GetOuterDelegateFrameTreeNodeId());
-  EXPECT_TRUE(outer_frame_tree_node);
-
-  EXPECT_TRUE(ExecJs(portal_contents->GetMainFrame(),
-                     "window.onportalactivate = e => "
-                     "document.body.appendChild(e.adoptPredecessor());"));
-
-  FrameDeletedObserver observer(outer_frame_tree_node->current_frame_host());
-  ExecuteScriptAsync(main_frame,
-                     "document.querySelector('portal').activate();");
-  observer.Wait();
-}
-
 class PortalOOPIFBrowserTest : public PortalBrowserTest {
  protected:
   PortalOOPIFBrowserTest() {}
diff --git a/content/browser/renderer_host/dwrite_font_lookup_table_builder_win.cc b/content/browser/renderer_host/dwrite_font_lookup_table_builder_win.cc
index 7137392..7b48e6da 100644
--- a/content/browser/renderer_host/dwrite_font_lookup_table_builder_win.cc
+++ b/content/browser/renderer_host/dwrite_font_lookup_table_builder_win.cc
@@ -6,7 +6,6 @@
 
 #include <dwrite.h>
 #include <dwrite_2.h>
-#include <algorithm>
 #include <set>
 #include <utility>
 
@@ -34,6 +33,7 @@
 #include "content/browser/renderer_host/dwrite_font_uma_logging_win.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/content_features.h"
+#include "third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h"
 #include "third_party/blink/public/common/font_unique_name_lookup/icu_fold_case_util.h"
 #include "ui/gfx/win/direct_write.h"
 
@@ -628,13 +628,8 @@
 
   unsigned num_font_files = font_unique_name_table->fonts_size();
 
-  // Sort names for using binary search on this proto in FontTableMatcher.
-  std::sort(font_unique_name_table->mutable_name_map()->begin(),
-            font_unique_name_table->mutable_name_map()->end(),
-            [](const blink::FontUniqueNameTable_UniqueNameToFontMapping& a,
-               const blink::FontUniqueNameTable_UniqueNameToFontMapping& b) {
-              return a.font_name() < b.font_name();
-            });
+  blink::FontTableMatcher::SortUniqueNameTableForSearch(
+      font_unique_name_table.get());
 
   font_table_memory_ = base::ReadOnlySharedMemoryRegion::Create(
       font_unique_name_table->ByteSizeLong());
diff --git a/content/browser/resources/media/stats_graph_helper.js b/content/browser/resources/media/stats_graph_helper.js
index b8e0d3a..46271ff3 100644
--- a/content/browser/resources/media/stats_graph_helper.js
+++ b/content/browser/resources/media/stats_graph_helper.js
@@ -168,9 +168,6 @@
   if (!stats || !stats.values) {
     return;
   }
-  if (!isLegacyReport && isStandardReportBlacklisted(report)) {
-    return;
-  }
 
   const childrenBefore = peerConnectionElement.hasChildNodes() ?
       Array.from(peerConnectionElement.childNodes) :
@@ -178,10 +175,6 @@
 
   for (var i = 0; i < stats.values.length - 1; i = i + 2) {
     var rawLabel = stats.values[i];
-    if (!isLegacyReport && isStandardStatBlacklisted(report, rawLabel)) {
-      continue;
-    }
-
     // Propagation deltas are handled separately.
     if (rawLabel == RECEIVED_PROPAGATION_DELTA_LABEL) {
       drawReceivedPropagationDelta(
@@ -198,7 +191,6 @@
           [stats.values[i + 1]]);
       continue;
     }
-
     var finalDataSeriesId = rawDataSeriesId;
     var finalLabel = rawLabel;
     var finalValue = rawValue;
@@ -223,6 +215,14 @@
         peerConnectionElement, finalDataSeriesId, finalLabel, [stats.timestamp],
         [finalValue]);
 
+    if (!isLegacyReport &&
+        (isStandardReportBlacklisted(report) ||
+         isStandardStatBlacklisted(report, rawLabel))) {
+      // We do not want to draw certain standard reports but still want to
+      // record them in the data series.
+      continue;
+    }
+
     // Updates the graph.
     var graphType =
         bweCompoundGraphConfig[finalLabel] ? 'bweCompound' : finalLabel;
diff --git a/content/browser/web_package/mock_signed_exchange_handler.cc b/content/browser/web_package/mock_signed_exchange_handler.cc
index 1b6829e7..19d826b9 100644
--- a/content/browser/web_package/mock_signed_exchange_handler.cc
+++ b/content/browser/web_package/mock_signed_exchange_handler.cc
@@ -21,14 +21,19 @@
     const GURL& inner_url,
     const std::string& mime_type,
     std::vector<std::string> response_headers,
-    base::Optional<net::SHA256HashValue> header_integrity)
+    base::Optional<net::SHA256HashValue> header_integrity,
+    const base::Time& signature_expire_time)
     : outer_url(outer_url),
       result(result),
       error(error),
       inner_url(inner_url),
       mime_type(mime_type),
       response_headers(std::move(response_headers)),
-      header_integrity(std::move(header_integrity)) {}
+      header_integrity(std::move(header_integrity)),
+      signature_expire_time(signature_expire_time.is_null()
+                                ? base::Time::Now() +
+                                      base::TimeDelta::FromDays(1)
+                                : signature_expire_time) {}
 
 MockSignedExchangeHandlerParams::MockSignedExchangeHandlerParams(
     const MockSignedExchangeHandlerParams& other) = default;
@@ -38,7 +43,8 @@
     const MockSignedExchangeHandlerParams& params,
     std::unique_ptr<net::SourceStream> body,
     ExchangeHeadersCallback headers_callback)
-    : header_integrity_(params.header_integrity) {
+    : header_integrity_(params.header_integrity),
+      signature_expire_time_(params.signature_expire_time) {
   network::ResourceResponseHead head;
   if (params.error == net::OK) {
     head.headers =
@@ -61,6 +67,10 @@
   return header_integrity_;
 }
 
+base::Time MockSignedExchangeHandler::GetSignatureExpireTime() const {
+  return signature_expire_time_;
+}
+
 MockSignedExchangeHandler::~MockSignedExchangeHandler() {}
 
 MockSignedExchangeHandlerFactory::MockSignedExchangeHandlerFactory(
diff --git a/content/browser/web_package/mock_signed_exchange_handler.h b/content/browser/web_package/mock_signed_exchange_handler.h
index 02038da..ab71024 100644
--- a/content/browser/web_package/mock_signed_exchange_handler.h
+++ b/content/browser/web_package/mock_signed_exchange_handler.h
@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 
+#include "base/time/time.h"
 #include "content/browser/web_package/signed_exchange_handler.h"
 #include "net/base/hash_value.h"
 #include "url/gurl.h"
@@ -19,6 +20,7 @@
 class MockSignedExchangeHandlerParams {
  public:
   // |mime_type| and |response_headers| are ignored if |error| is not net::OK.
+  // If |signature_expire_time| is a null Time, we treat as one day after now.
   MockSignedExchangeHandlerParams(
       const GURL& outer_url,
       SignedExchangeLoadResult result,
@@ -26,7 +28,8 @@
       const GURL& inner_url,
       const std::string& mime_type,
       std::vector<std::string> response_headers,
-      base::Optional<net::SHA256HashValue> header_integrity);
+      base::Optional<net::SHA256HashValue> header_integrity,
+      const base::Time& signature_expire_time = base::Time());
   MockSignedExchangeHandlerParams(const MockSignedExchangeHandlerParams& other);
   ~MockSignedExchangeHandlerParams();
   const GURL outer_url;
@@ -36,6 +39,7 @@
   const std::string mime_type;
   const std::vector<std::string> response_headers;
   const base::Optional<net::SHA256HashValue> header_integrity;
+  const base::Time signature_expire_time;
 };
 
 class MockSignedExchangeHandler final : public SignedExchangeHandler {
@@ -45,9 +49,11 @@
                             ExchangeHeadersCallback headers_callback);
   ~MockSignedExchangeHandler() override;
   base::Optional<net::SHA256HashValue> ComputeHeaderIntegrity() const override;
+  base::Time GetSignatureExpireTime() const override;
 
  private:
   const base::Optional<net::SHA256HashValue> header_integrity_;
+  const base::Time signature_expire_time_;
 
   DISALLOW_COPY_AND_ASSIGN(MockSignedExchangeHandler);
 };
diff --git a/content/browser/web_package/prefetched_signed_exchange_cache.cc b/content/browser/web_package/prefetched_signed_exchange_cache.cc
index 51cfba5a..346e3cd 100644
--- a/content/browser/web_package/prefetched_signed_exchange_cache.cc
+++ b/content/browser/web_package/prefetched_signed_exchange_cache.cc
@@ -376,10 +376,6 @@
       ResourceContext* resource_context,
       LoaderCallback callback,
       FallbackCallback fallback_callback) override {
-    // Currently we just check the URL matching. But we should check the Vary
-    // header (eg: HttpVaryData::MatchesRequest()) and Cache-Control header.
-    // And also we shuold check the expires parameter of the signed exchange's
-    // signature. TODO(crbug.com/935267): Implement these checking logic.
     if (state_ == State::kInitial &&
         tentative_resource_request.url == exchange_->outer_url()) {
       state_ = State::kOuterRequestRequested;
@@ -470,22 +466,25 @@
   return true;
 }
 
-bool CanUseEntry(const PrefetchedSignedExchangeCache::Entry& entry) {
+bool CanUseEntry(const PrefetchedSignedExchangeCache::Entry& entry,
+                 const base::Time& now) {
+  if (entry.signature_expire_time() < now)
+    return false;
+
   const std::unique_ptr<const network::ResourceResponseHead>& outer_response =
       entry.outer_response();
+
   // Use the prefetched entry within kPrefetchReuseMins minutes without
   // validation.
-  if (outer_response->headers->GetCurrentAge(outer_response->request_time,
-                                             outer_response->response_time,
-                                             base::Time::Now()) <
+  if (outer_response->headers->GetCurrentAge(
+          outer_response->request_time, outer_response->response_time, now) <
       base::TimeDelta::FromMinutes(net::HttpCache::kPrefetchReuseMins)) {
     return true;
   }
   // We use the prefetched entry when we don't need the validation.
   if (outer_response->headers->RequiresValidation(
-          outer_response->request_time, outer_response->response_time,
-          base::Time::Now()) != net::VALIDATION_NONE) {
-    // TODO(crbug.com/935267): Consider discarding this entry.
+          outer_response->request_time, outer_response->response_time, now) !=
+      net::VALIDATION_NONE) {
     return false;
   }
   return true;
@@ -523,6 +522,10 @@
     std::unique_ptr<const storage::BlobDataHandle> blob_data_handle) {
   blob_data_handle_ = std::move(blob_data_handle);
 }
+void PrefetchedSignedExchangeCache::Entry::SetSignatureExpireTime(
+    const base::Time& signature_expire_time) {
+  signature_expire_time_ = signature_expire_time;
+}
 
 std::unique_ptr<const PrefetchedSignedExchangeCache::Entry>
 PrefetchedSignedExchangeCache::Entry::Clone() const {
@@ -533,6 +536,7 @@
   DCHECK(inner_response());
   DCHECK(completion_status());
   DCHECK(blob_data_handle());
+  DCHECK(!signature_expire_time().is_null());
 
   std::unique_ptr<Entry> clone = std::make_unique<Entry>();
   clone->SetOuterUrl(outer_url_);
@@ -548,6 +552,7 @@
           *completion_status_));
   clone->SetBlobDataHandle(
       std::make_unique<const storage::BlobDataHandle>(*blob_data_handle_));
+  clone->SetSignatureExpireTime(signature_expire_time_);
   return clone;
 }
 
@@ -572,6 +577,7 @@
   DCHECK(cached_exchange->inner_response());
   DCHECK(cached_exchange->completion_status());
   DCHECK(cached_exchange->blob_data_handle());
+  DCHECK(!cached_exchange->signature_expire_time().is_null());
 
   if (!CanStoreEntry(*cached_exchange))
     return;
@@ -585,12 +591,15 @@
   const auto it = exchanges_.find(outer_url);
   if (it == exchanges_.end())
     return nullptr;
+  const base::Time now = base::Time::Now();
   const std::unique_ptr<const Entry>& exchange = it->second;
-  if (!CanUseEntry(*exchange.get()))
+  if (!CanUseEntry(*exchange.get(), now)) {
+    exchanges_.erase(it);
     return nullptr;
+  }
   return std::make_unique<PrefetchedNavigationLoaderInterceptor>(
       exchange->Clone(),
-      GetInfoListForNavigation(outer_url, exchange->inner_url()));
+      GetInfoListForNavigation(outer_url, exchange->inner_url(), now));
 }
 
 const PrefetchedSignedExchangeCache::EntryMap&
@@ -632,9 +641,9 @@
 }
 
 std::vector<PrefetchedSignedExchangeInfo>
-PrefetchedSignedExchangeCache::GetInfoListForNavigation(
-    const GURL& outer_url,
-    const GURL& inner_url) const {
+PrefetchedSignedExchangeCache::GetInfoListForNavigation(const GURL& outer_url,
+                                                        const GURL& inner_url,
+                                                        const base::Time& now) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (!base::FeatureList::IsEnabled(
@@ -648,24 +657,28 @@
   const url::Origin outer_url_origin = url::Origin::Create(outer_url);
   const url::Origin inner_url_origin = url::Origin::Create(inner_url);
 
-  for (const auto& exchanges_it : exchanges_) {
-    const std::unique_ptr<const Entry>& exchange = exchanges_it.second;
-    if (!outer_url_origin.IsSameOriginWith(
-            url::Origin::Create(exchange->outer_url()))) {
-      // Restrict the main SXG and the subresources SXGs to be served from the
-      // same origin.
+  EntryMap::iterator exchanges_it = exchanges_.begin();
+  while (exchanges_it != exchanges_.end()) {
+    const std::unique_ptr<const Entry>& exchange = exchanges_it->second;
+    if (!CanUseEntry(*exchange.get(), now)) {
+      exchanges_.erase(exchanges_it++);
       continue;
     }
-    if (!CanUseEntry(*exchange.get()))
-      continue;
-    network::mojom::URLLoaderFactoryPtrInfo loader_factory_info;
-    new SubresourceSignedExchangeURLLoaderFactory(
-        mojo::MakeRequest(&loader_factory_info), exchange->Clone(),
-        inner_url_origin);
-    info_list.emplace_back(
-        exchange->outer_url(), *exchange->header_integrity(),
-        exchange->inner_url(), *exchange->inner_response(),
-        std::move(loader_factory_info).PassHandle().release());
+
+    // Restrict the main SXG and the subresources SXGs to be served from the
+    // same origin.
+    if (outer_url_origin.IsSameOriginWith(
+            url::Origin::Create(exchange->outer_url()))) {
+      network::mojom::URLLoaderFactoryPtrInfo loader_factory_info;
+      new SubresourceSignedExchangeURLLoaderFactory(
+          mojo::MakeRequest(&loader_factory_info), exchange->Clone(),
+          inner_url_origin);
+      info_list.emplace_back(
+          exchange->outer_url(), *exchange->header_integrity(),
+          exchange->inner_url(), *exchange->inner_response(),
+          std::move(loader_factory_info).PassHandle().release());
+    }
+    ++exchanges_it;
   }
   return info_list;
 }
diff --git a/content/browser/web_package/prefetched_signed_exchange_cache.h b/content/browser/web_package/prefetched_signed_exchange_cache.h
index 48d940dd..267404d 100644
--- a/content/browser/web_package/prefetched_signed_exchange_cache.h
+++ b/content/browser/web_package/prefetched_signed_exchange_cache.h
@@ -8,6 +8,7 @@
 #include <map>
 
 #include "base/memory/ref_counted.h"
+#include "base/time/time.h"
 #include "content/common/content_export.h"
 #include "content/common/prefetched_signed_exchange_info.h"
 #include "net/base/hash_value.h"
@@ -65,6 +66,7 @@
         const {
       return blob_data_handle_;
     }
+    base::Time signature_expire_time() const { return signature_expire_time_; }
 
     void SetOuterUrl(const GURL& outer_url);
     void SetOuterResponse(
@@ -79,6 +81,7 @@
             completion_status);
     void SetBlobDataHandle(
         std::unique_ptr<const storage::BlobDataHandle> blob_data_handle);
+    void SetSignatureExpireTime(const base::Time& signature_expire_time);
 
     std::unique_ptr<const Entry> Clone() const;
 
@@ -91,6 +94,7 @@
     std::unique_ptr<const network::URLLoaderCompletionStatus>
         completion_status_;
     std::unique_ptr<const storage::BlobDataHandle> blob_data_handle_;
+    base::Time signature_expire_time_;
 
     DISALLOW_COPY_AND_ASSIGN(Entry);
   };
@@ -112,9 +116,14 @@
   friend class base::RefCountedThreadSafe<PrefetchedSignedExchangeCache>;
 
   ~PrefetchedSignedExchangeCache();
+
+  // Returns PrefetchedSignedExchangeInfo of entries in |exchanges_| which are
+  // not expired and which outer URL's origin is same as the origin of
+  // |outer_url|. Note that this method erases expired entries in |exchanges_|.
   std::vector<PrefetchedSignedExchangeInfo> GetInfoListForNavigation(
       const GURL& outer_url,
-      const GURL& inner_url) const;
+      const GURL& inner_url,
+      const base::Time& now);
 
   EntryMap exchanges_;
 
diff --git a/content/browser/web_package/prefetched_signed_exchange_cache_adapter.cc b/content/browser/web_package/prefetched_signed_exchange_cache_adapter.cc
index e8f4adc..d64bb19 100644
--- a/content/browser/web_package/prefetched_signed_exchange_cache_adapter.cc
+++ b/content/browser/web_package/prefetched_signed_exchange_cache_adapter.cc
@@ -38,11 +38,14 @@
 
 void PrefetchedSignedExchangeCacheAdapter::OnReceiveRedirect(
     const GURL& new_url,
-    const base::Optional<net::SHA256HashValue> header_integrity) {
+    const base::Optional<net::SHA256HashValue> header_integrity,
+    const base::Time& signature_expire_time) {
   DCHECK(header_integrity);
+  DCHECK(!signature_expire_time.is_null());
   cached_exchange_->SetHeaderIntegrity(
       std::make_unique<net::SHA256HashValue>(*header_integrity));
   cached_exchange_->SetInnerUrl(new_url);
+  cached_exchange_->SetSignatureExpireTime(signature_expire_time);
 }
 
 void PrefetchedSignedExchangeCacheAdapter::OnReceiveInnerResponse(
diff --git a/content/browser/web_package/prefetched_signed_exchange_cache_adapter.h b/content/browser/web_package/prefetched_signed_exchange_cache_adapter.h
index 135b9cf..82e271f2 100644
--- a/content/browser/web_package/prefetched_signed_exchange_cache_adapter.h
+++ b/content/browser/web_package/prefetched_signed_exchange_cache_adapter.h
@@ -11,9 +11,13 @@
 
 class GURL;
 
+namespace base {
+class Time;
+}  // namespace base
+
 namespace net {
 struct SHA256HashValue;
-}
+}  // namespace net
 
 namespace storage {
 class BlobBuilderFromStream;
@@ -38,7 +42,8 @@
   void OnReceiveOuterResponse(const network::ResourceResponseHead& response);
   void OnReceiveRedirect(
       const GURL& new_url,
-      const base::Optional<net::SHA256HashValue> header_integrity);
+      const base::Optional<net::SHA256HashValue> header_integrity,
+      const base::Time& signature_expire_time);
   void OnReceiveInnerResponse(const network::ResourceResponseHead& response);
   void OnStartLoadingResponseBody(mojo::ScopedDataPipeConsumerHandle body);
   void OnComplete(const network::URLLoaderCompletionStatus& status);
diff --git a/content/browser/web_package/signed_exchange_handler.cc b/content/browser/web_package/signed_exchange_handler.cc
index 22fad8e..95d3641b3 100644
--- a/content/browser/web_package/signed_exchange_handler.cc
+++ b/content/browser/web_package/signed_exchange_handler.cc
@@ -790,4 +790,10 @@
   return envelope_->ComputeHeaderIntegrity();
 }
 
+base::Time SignedExchangeHandler::GetSignatureExpireTime() const {
+  if (!envelope_)
+    return base::Time();
+  return base::Time::UnixEpoch() +
+         base::TimeDelta::FromSeconds(envelope_->signature().expires);
+}
 }  // namespace content
diff --git a/content/browser/web_package/signed_exchange_handler.h b/content/browser/web_package/signed_exchange_handler.h
index 351ebd8..7ac5fd7 100644
--- a/content/browser/web_package/signed_exchange_handler.h
+++ b/content/browser/web_package/signed_exchange_handler.h
@@ -106,6 +106,11 @@
   // Otherwise returns nullopt.
   virtual base::Optional<net::SHA256HashValue> ComputeHeaderIntegrity() const;
 
+  // Returns the signature expire time of the loaded signed exchange if
+  // available. This is available after |headers_callback| is called.
+  // Otherwise returns a null Time.
+  virtual base::Time GetSignatureExpireTime() const;
+
  protected:
   SignedExchangeHandler();
 
diff --git a/content/browser/web_package/signed_exchange_loader.cc b/content/browser/web_package/signed_exchange_loader.cc
index dd58fdb..4788305 100644
--- a/content/browser/web_package/signed_exchange_loader.cc
+++ b/content/browser/web_package/signed_exchange_loader.cc
@@ -225,6 +225,12 @@
   return signed_exchange_handler_->ComputeHeaderIntegrity();
 }
 
+base::Time SignedExchangeLoader::GetSignatureExpireTime() const {
+  if (!signed_exchange_handler_)
+    return base::Time();
+  return signed_exchange_handler_->GetSignatureExpireTime();
+}
+
 void SignedExchangeLoader::OnHTTPExchangeFound(
     SignedExchangeLoadResult result,
     net::Error error,
diff --git a/content/browser/web_package/signed_exchange_loader.h b/content/browser/web_package/signed_exchange_loader.h
index c14193b..2856875 100644
--- a/content/browser/web_package/signed_exchange_loader.h
+++ b/content/browser/web_package/signed_exchange_loader.h
@@ -10,6 +10,7 @@
 
 #include "base/callback.h"
 #include "base/optional.h"
+#include "base/time/time.h"
 #include "base/unguessable_token.h"
 #include "content/browser/web_package/signed_exchange_error.h"
 #include "content/common/content_export.h"
@@ -111,6 +112,11 @@
   // |forwarding_client| is called. Otherwise returns nullopt.
   base::Optional<net::SHA256HashValue> ComputeHeaderIntegrity() const;
 
+  // Returns the signature expire time of the loaded signed exchange if
+  // available. This is available after OnReceiveRedirect() of
+  // |forwarding_client| is called. Otherwise returns a null Time.
+  base::Time GetSignatureExpireTime() const;
+
   // Set nullptr to reset the mocking.
   static void SetSignedExchangeHandlerFactoryForTest(
       SignedExchangeHandlerFactory* factory);
diff --git a/content/browser/web_package/signed_exchange_prefetch_handler.cc b/content/browser/web_package/signed_exchange_prefetch_handler.cc
index 8a0a2b0..c48d1d9 100644
--- a/content/browser/web_package/signed_exchange_prefetch_handler.cc
+++ b/content/browser/web_package/signed_exchange_prefetch_handler.cc
@@ -84,6 +84,12 @@
   return signed_exchange_loader_->ComputeHeaderIntegrity();
 }
 
+base::Time SignedExchangePrefetchHandler::GetSignatureExpireTime() const {
+  if (!signed_exchange_loader_)
+    return base::Time();
+  return signed_exchange_loader_->GetSignatureExpireTime();
+}
+
 void SignedExchangePrefetchHandler::OnReceiveResponse(
     const network::ResourceResponseHead& head) {
   NOTREACHED();
diff --git a/content/browser/web_package/signed_exchange_prefetch_handler.h b/content/browser/web_package/signed_exchange_prefetch_handler.h
index 2943a606..37faf28 100644
--- a/content/browser/web_package/signed_exchange_prefetch_handler.h
+++ b/content/browser/web_package/signed_exchange_prefetch_handler.h
@@ -10,6 +10,7 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/optional.h"
+#include "base/time/time.h"
 #include "base/unguessable_token.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
@@ -71,6 +72,12 @@
   // called. Otherwise returns nullopt.
   base::Optional<net::SHA256HashValue> ComputeHeaderIntegrity() const;
 
+  // Returns the signature expire time of the loaded signed exchange if
+  // available. This is available after OnReceiveRedirect() of
+  // |forwarding_client| is called and before FollowRedirect() of |this| is
+  // called. Otherwise returns a null Time.
+  base::Time GetSignatureExpireTime() const;
+
  private:
   // network::mojom::URLLoaderClient overrides:
   void OnReceiveResponse(const network::ResourceResponseHead& head) override;
diff --git a/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc b/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
index 9971f299..0d17831 100644
--- a/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
+++ b/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
@@ -300,8 +300,8 @@
       const std::string& inner_url_path,
       const net::SHA256HashValue& header_integrity,
       const std::string& content,
-      const std::vector<std::pair<std::string, std::string>>&
-          sxg_outer_headers) {
+      const std::vector<std::pair<std::string, std::string>>& sxg_outer_headers,
+      const base::Time& signature_expire_time = base::Time()) {
     auto sxg_request_counter =
         RequestCounter::CreateAndMonitor(embedded_test_server(), sxg_path);
     RegisterRequestHandler(embedded_test_server());
@@ -322,7 +322,7 @@
 
     MockSignedExchangeHandlerFactory factory({MockSignedExchangeHandlerParams(
         sxg_url, SignedExchangeLoadResult::kSuccess, net::OK, inner_url,
-        "text/html", {}, header_integrity)});
+        "text/html", {}, header_integrity, signature_expire_time)});
     ScopedSignedExchangeHandlerFactory scoped_factory(&factory);
 
     EXPECT_EQ(0, sxg_request_counter->GetRequestCount());
@@ -580,6 +580,56 @@
   EXPECT_EQ(2, sxg_request_counter->GetRequestCount());
 }
 
+IN_PROC_BROWSER_TEST_P(SignedExchangePrefetchBrowserTest,
+                       PrefetchMainResourceSXG_SignatureExpire) {
+  const char* hostname = "example.com";
+  const char* sxg_path = "/target.sxg";
+  const char* inner_url_path = "/target.html";
+  const std::string content =
+      "<head><title>Prefetch Target (SXG)</title></head>";
+  auto sxg_request_counter =
+      RequestCounter::CreateAndMonitor(embedded_test_server(), sxg_path);
+
+  LoadPrefetchMainResourceSXGTestPage(
+      hostname, "/prefetch.html" /* prefetch_page_path */, hostname, sxg_path,
+      hostname, inner_url_path,
+      net::SHA256HashValue({{0x01}}) /* header_integrity */, content,
+      {} /* sxg_outer_headers */,
+      base::Time::Now() +
+          base::TimeDelta::FromMinutes(net::HttpCache::kPrefetchReuseMins * 2));
+  EXPECT_EQ(1, sxg_request_counter->GetRequestCount());
+
+  const GURL sxg_url = embedded_test_server()->GetURL(hostname, sxg_path);
+  const GURL inner_url =
+      embedded_test_server()->GetURL(hostname, inner_url_path);
+
+  EXPECT_EQ(1u, GetCachedExchanges(shell()).size());
+
+  MockClock::Get().Advance(
+      base::TimeDelta::FromMinutes(net::HttpCache::kPrefetchReuseMins * 3));
+
+  // Setup MockSignedExchangeHandlerFactory which triggers signature
+  // verificvation error fallback.
+  MockSignedExchangeHandlerFactory factory({MockSignedExchangeHandlerParams(
+      sxg_url, SignedExchangeLoadResult::kSignatureVerificationError,
+      net::ERR_INVALID_SIGNED_EXCHANGE, inner_url, "",
+      {} /* sxg_inner_headers */,
+      net::SHA256HashValue({{0x01}}) /* header_integrity */)});
+  ScopedSignedExchangeHandlerFactory scoped_factory(&factory);
+
+  RegisterResponse(inner_url_path, ResponseEntry("<title>from server</title>"));
+
+  NavigateToURLAndWaitTitle(sxg_url, "from server");
+
+  // SXG must be fetched again, because:
+  //  - The entry in PrefetchedSignedExchangeCache is expired (signature expire
+  //    time).
+  //  - The entry in HTTPCache is expired (more than kPrefetchReuseMins minutes
+  //    passed). Note: The prefetched resource can skip cache revalidation for
+  //    kPrefetchReuseMins minutes.
+  EXPECT_EQ(2, sxg_request_counter->GetRequestCount());
+}
+
 // This test is almost same as SignedExchangeSubresourcePrefetchBrowserTest's
 // MainResourceSXGAndScriptSXG_SameOrigin. The only difference is that this test
 // is executed without SignedExchangeSubresourcePrefetch but with
diff --git a/content/common/navigation_params.mojom b/content/common/navigation_params.mojom
index 634e3b7..a8d8027 100644
--- a/content/common/navigation_params.mojom
+++ b/content/common/navigation_params.mojom
@@ -41,6 +41,9 @@
   // Whether or not the navigation has been initiated by a form submission.
   bool is_form_submission;
 
+ // Whether or not the navigation has been initiated by a link click.
+  bool was_initiated_by_link_click;
+
   // See WebSearchableFormData for a description of these.
   url.mojom.Url searchable_form_url;
   string searchable_form_encoding;
diff --git a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java
index 650f5a7..b906955 100644
--- a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java
@@ -455,6 +455,13 @@
         resourceExtractor.startExtractingResources("en");
         resourceExtractor.waitForCompletion();
         nativeSetCommandLineFlags(false);
+
+        mFullBrowserStartupDone = true;
+        mStartupSuccess = true;
+        for (StartupCallback asyncStartupCallback : mAsyncStartupCallbacks) {
+            asyncStartupCallback.onSuccess();
+        }
+        mAsyncStartupCallbacks.clear();
     }
 
     private static native void nativeSetCommandLineFlags(boolean singleProcess);
diff --git a/content/public/browser/navigation_handle.h b/content/public/browser/navigation_handle.h
index 7436eb4..da5e13ae 100644
--- a/content/public/browser/navigation_handle.h
+++ b/content/public/browser/navigation_handle.h
@@ -289,6 +289,9 @@
   // Returns true if this navigation was initiated by a form submission.
   virtual bool IsFormSubmission() = 0;
 
+  // Returns true if this navigation was initiated by a link click.
+  virtual bool WasInitiatedByLinkClick() = 0;
+
   // Returns true if the target is an inner response of a signed exchange.
   virtual bool IsSignedExchangeInnerResponse() = 0;
 
diff --git a/content/public/test/mock_navigation_handle.h b/content/public/test/mock_navigation_handle.h
index 554a7c4..73c5faf 100644
--- a/content/public/test/mock_navigation_handle.h
+++ b/content/public/test/mock_navigation_handle.h
@@ -85,6 +85,7 @@
   MOCK_METHOD0(GetGlobalRequestID, const GlobalRequestID&());
   MOCK_METHOD0(IsDownload, bool());
   bool IsFormSubmission() override { return is_form_submission_; }
+  MOCK_METHOD0(WasInitiatedByLinkClick, bool());
   MOCK_METHOD0(IsSignedExchangeInnerResponse, bool());
   bool WasResponseCached() override { return was_response_cached_; }
   const net::ProxyServer& GetProxyServer() override { return proxy_server_; }
diff --git a/content/public/test/navigation_simulator.h b/content/public/test/navigation_simulator.h
index 27ee934..9315dae7 100644
--- a/content/public/test/navigation_simulator.h
+++ b/content/public/test/navigation_simulator.h
@@ -245,6 +245,9 @@
   // Sets whether this navigation originated as the result of a form submission.
   virtual void SetIsFormSubmission(bool is_form_submission) = 0;
 
+  // Sets whether this navigation originated as the result of a link click.
+  virtual void SetWasInitiatedByLinkClick(bool was_initiated_by_link_click) = 0;
+
   // The following parameters can change during redirects. They should be
   // specified before calling |Start| if they need to apply to the navigation to
   // the original url. Otherwise, they should be specified before calling
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 4468c0b2..9a1ee08c 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -42,9 +42,6 @@
     "accessibility/blink_ax_tree_source.h",
     "accessibility/render_accessibility_impl.cc",
     "accessibility/render_accessibility_impl.h",
-    "android/synchronous_compositor_proxy.cc",
-    "android/synchronous_compositor_proxy.h",
-    "android/synchronous_compositor_registry.h",
     "android/synchronous_layer_tree_frame_sink.cc",
     "android/synchronous_layer_tree_frame_sink.h",
     "blob_storage/webblobregistry_impl.cc",
@@ -661,9 +658,15 @@
   }
 
   if (is_android) {
-    # Add back the Linux file which Android shares.
     set_sources_assignment_filter([])
-    sources += [ "render_view_linux.cc" ]
+    sources += [
+      "input/synchronous_compositor_proxy.cc",
+      "input/synchronous_compositor_proxy.h",
+      "input/synchronous_compositor_registry.h",
+
+      # Add back the Linux file which Android shares.
+      "render_view_linux.cc",
+    ]
     set_sources_assignment_filter(sources_assignment_filter)
 
     deps += [
diff --git a/content/renderer/android/synchronous_layer_tree_frame_sink.cc b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
index b836637..4842e09 100644
--- a/content/renderer/android/synchronous_layer_tree_frame_sink.cc
+++ b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
@@ -28,8 +28,8 @@
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "content/common/view_messages.h"
-#include "content/renderer/android/synchronous_compositor_registry.h"
 #include "content/renderer/frame_swap_message_queue.h"
+#include "content/renderer/input/synchronous_compositor_registry.h"
 #include "content/renderer/render_thread_impl.h"
 #include "gpu/command_buffer/client/context_support.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
diff --git a/content/renderer/android/synchronous_compositor_proxy.cc b/content/renderer/input/synchronous_compositor_proxy.cc
similarity index 99%
rename from content/renderer/android/synchronous_compositor_proxy.cc
rename to content/renderer/input/synchronous_compositor_proxy.cc
index 86853a50..a0a0a74 100644
--- a/content/renderer/android/synchronous_compositor_proxy.cc
+++ b/content/renderer/input/synchronous_compositor_proxy.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 "content/renderer/android/synchronous_compositor_proxy.h"
+#include "content/renderer/input/synchronous_compositor_proxy.h"
 
 #include "base/auto_reset.h"
 #include "base/bind.h"
diff --git a/content/renderer/android/synchronous_compositor_proxy.h b/content/renderer/input/synchronous_compositor_proxy.h
similarity index 96%
rename from content/renderer/android/synchronous_compositor_proxy.h
rename to content/renderer/input/synchronous_compositor_proxy.h
index 8d52395..ffa72ca4 100644
--- a/content/renderer/android/synchronous_compositor_proxy.h
+++ b/content/renderer/input/synchronous_compositor_proxy.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 CONTENT_RENDERER_ANDROID_SYNCHRONOUS_COMPOSITOR_PROXY_H_
-#define CONTENT_RENDERER_ANDROID_SYNCHRONOUS_COMPOSITOR_PROXY_H_
+#ifndef CONTENT_RENDERER_INPUT_SYNCHRONOUS_COMPOSITOR_PROXY_H_
+#define CONTENT_RENDERER_INPUT_SYNCHRONOUS_COMPOSITOR_PROXY_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -151,4 +151,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_RENDERER_ANDROID_SYNCHRONOUS_COMPOSITOR_PROXY_H_
+#endif  // CONTENT_RENDERER_INPUT_SYNCHRONOUS_COMPOSITOR_PROXY_H_
diff --git a/content/renderer/android/synchronous_compositor_registry.h b/content/renderer/input/synchronous_compositor_registry.h
similarity index 74%
rename from content/renderer/android/synchronous_compositor_registry.h
rename to content/renderer/input/synchronous_compositor_registry.h
index 588343c..5d57d424 100644
--- a/content/renderer/android/synchronous_compositor_registry.h
+++ b/content/renderer/input/synchronous_compositor_registry.h
@@ -2,9 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_RENDERER_ANDROID_SYNCHRONOUS_COMPOSITOR_REGISTRY_H_
-#define CONTENT_RENDERER_ANDROID_SYNCHRONOUS_COMPOSITOR_REGISTRY_H_
-
+#ifndef CONTENT_RENDERER_INPUT_SYNCHRONOUS_COMPOSITOR_REGISTRY_H_
+#define CONTENT_RENDERER_INPUT_SYNCHRONOUS_COMPOSITOR_REGISTRY_H_
 
 namespace content {
 class SynchronousLayerTreeFrameSink;
@@ -24,4 +23,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_RENDERER_ANDROID_SYNCHRONOUS_COMPOSITOR_REGISTRY_H_
+#endif  // CONTENT_RENDERER_INPUT_SYNCHRONOUS_COMPOSITOR_REGISTRY_H_
diff --git a/content/renderer/input/widget_input_handler_manager.cc b/content/renderer/input/widget_input_handler_manager.cc
index 098ecd5f..ca70ecb 100644
--- a/content/renderer/input/widget_input_handler_manager.cc
+++ b/content/renderer/input/widget_input_handler_manager.cc
@@ -24,8 +24,8 @@
 
 #if defined(OS_ANDROID)
 #include "content/public/common/content_client.h"
-#include "content/renderer/android/synchronous_compositor_proxy.h"
-#include "content/renderer/android/synchronous_compositor_registry.h"
+#include "content/renderer/input/synchronous_compositor_proxy.h"
+#include "content/renderer/input/synchronous_compositor_registry.h"
 #endif
 
 namespace content {
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 2025cc5..ec9a973c 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -7104,6 +7104,9 @@
       info->navigation_type == blink::kWebNavigationTypeFormSubmitted ||
       info->navigation_type == blink::kWebNavigationTypeFormResubmitted;
 
+  bool was_initiated_by_link_click =
+      info->navigation_type == blink::kWebNavigationTypeLinkClicked;
+
   GURL searchable_form_url;
   std::string searchable_form_encoding;
   if (!info->form.IsNull()) {
@@ -7128,8 +7131,8 @@
           info->url_request.GetSkipServiceWorker(),
           GetRequestContextTypeForWebURLRequest(info->url_request),
           GetMixedContentContextTypeForWebURLRequest(info->url_request),
-          is_form_submission, searchable_form_url, searchable_form_encoding,
-          client_side_redirect_url,
+          is_form_submission, was_initiated_by_link_click, searchable_form_url,
+          searchable_form_encoding, client_side_redirect_url,
           initiator ? base::make_optional<base::Value>(std::move(*initiator))
                     : base::nullopt);
 
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc
index 195bd76..44e5f00 100644
--- a/content/test/navigation_simulator_impl.cc
+++ b/content/test/navigation_simulator_impl.cc
@@ -847,6 +847,13 @@
   is_form_submission_ = is_form_submission;
 }
 
+void NavigationSimulatorImpl::SetWasInitiatedByLinkClick(
+    bool was_initiated_by_link_click) {
+  CHECK_EQ(INITIALIZATION, state_) << "The form submission parameter cannot "
+                                      "be set after the navigation has started";
+  was_initiated_by_link_click_ = was_initiated_by_link_click;
+}
+
 void NavigationSimulatorImpl::SetReferrer(const Referrer& referrer) {
   CHECK_LE(state_, STARTED) << "The referrer cannot be set after the "
                                "navigation has committed or has failed";
@@ -1077,7 +1084,7 @@
           false /* skip_service_worker */,
           blink::mojom::RequestContextType::HYPERLINK,
           blink::WebMixedContentContextType::kBlockable, is_form_submission_,
-          GURL() /* searchable_form_url */,
+          was_initiated_by_link_click_, GURL() /* searchable_form_url */,
           std::string() /* searchable_form_encoding */,
           GURL() /* client_side_redirect_url */,
           base::nullopt /* detools_initiator_info */);
diff --git a/content/test/navigation_simulator_impl.h b/content/test/navigation_simulator_impl.h
index 3aa1da5d..2a23e12 100644
--- a/content/test/navigation_simulator_impl.h
+++ b/content/test/navigation_simulator_impl.h
@@ -84,6 +84,7 @@
   void SetReloadType(ReloadType reload_type) override;
   void SetMethod(const std::string& method) override;
   void SetIsFormSubmission(bool is_form_submission) override;
+  void SetWasInitiatedByLinkClick(bool was_initiated_by_link_click) override;
   void SetReferrer(const Referrer& referrer) override;
   void SetSocketAddress(const net::IPEndPoint& remote_endpoint) override;
   void SetWasFetchedViaCache(bool was_fetched_via_cache) override;
@@ -264,6 +265,7 @@
   bool is_signed_exchange_inner_response_ = false;
   std::string initial_method_;
   bool is_form_submission_ = false;
+  bool was_initiated_by_link_click_ = false;
   bool browser_initiated_;
   bool same_document_ = false;
   Referrer referrer_;
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index c72007e..4d1c1ce6 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -329,7 +329,9 @@
           false /* skip_service_worker */,
           blink::mojom::RequestContextType::HYPERLINK,
           blink::WebMixedContentContextType::kBlockable,
-          false /* is_form_submission */, GURL() /* searchable_form_url */,
+          false /* is_form_submission */,
+          false /* was_initiated_by_link_click */,
+          GURL() /* searchable_form_url */,
           std::string() /* searchable_form_encoding */,
           GURL() /* client_side_redirect_url */,
           base::nullopt /* devtools_initiator_info */);
diff --git a/gpu/command_buffer/service/skia_utils.cc b/gpu/command_buffer/service/skia_utils.cc
index bb82e21d..ec81f696 100644
--- a/gpu/command_buffer/service/skia_utils.cc
+++ b/gpu/command_buffer/service/skia_utils.cc
@@ -7,7 +7,6 @@
 #include "base/logging.h"
 #include "components/viz/common/gpu/vulkan_context_provider.h"
 #include "components/viz/common/resources/resource_format_utils.h"
-#include "gpu/command_buffer/service/shared_context_state.h"
 #include "third_party/skia/include/gpu/GrBackendSurface.h"
 #include "third_party/skia/include/gpu/gl/GrGLTypes.h"
 #include "ui/gfx/geometry/size.h"
@@ -91,27 +90,4 @@
 #endif
 }
 
-void DeleteGrBackendTexture(SharedContextState* context_state,
-                            GrBackendTexture* backend_texture) {
-  DCHECK(backend_texture && backend_texture->isValid());
-  if (!context_state->GrContextIsVulkan()) {
-    context_state->gr_context()->deleteBackendTexture(
-        std::move(*backend_texture));
-    return;
-  }
-
-#if BUILDFLAG(ENABLE_VULKAN)
-  auto* fence_helper =
-      context_state->vk_context_provider()->GetDeviceQueue()->GetFenceHelper();
-  fence_helper->EnqueueCleanupTaskForSubmittedWork(base::BindOnce(
-      [](const sk_sp<GrContext>& gr_context, GrBackendTexture backend_texture,
-         gpu::VulkanDeviceQueue* device_queue, bool is_lost) {
-        // If underlying Vulkan device is destroyed, gr_context should have been
-        // abandoned, the deleteBackendTexture() should be noop.
-        gr_context->deleteBackendTexture(std::move(backend_texture));
-      },
-      sk_ref_sp(context_state->gr_context()), std::move(*backend_texture)));
-#endif
-}
-
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/skia_utils.h b/gpu/command_buffer/service/skia_utils.h
index e5e1a965..3edf8b47 100644
--- a/gpu/command_buffer/service/skia_utils.h
+++ b/gpu/command_buffer/service/skia_utils.h
@@ -31,9 +31,6 @@
 }  // namespace viz
 
 namespace gpu {
-
-class SharedContextState;
-
 // Creates a GrBackendTexture from a service ID. Skia does not take ownership.
 // Returns true on success.
 GPU_GLES2_EXPORT bool GetGrBackendTexture(const gl::GLVersionInfo* version_info,
@@ -53,9 +50,6 @@
     viz::VulkanContextProvider* context_provider,
     GrFlushInfo* flush_info);
 
-GPU_GLES2_EXPORT void DeleteGrBackendTexture(
-    SharedContextState* context_state,
-    GrBackendTexture* backend_textures);
 }  // namespace gpu
 
 #endif  // GPU_COMMAND_BUFFER_SERVICE_SKIA_UTILS_H_
diff --git a/gpu/command_buffer/service/wrapped_sk_image.cc b/gpu/command_buffer/service/wrapped_sk_image.cc
index a35f288..8a80586 100644
--- a/gpu/command_buffer/service/wrapped_sk_image.cc
+++ b/gpu/command_buffer/service/wrapped_sk_image.cc
@@ -17,7 +17,6 @@
 #include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/command_buffer/service/shared_image_backing.h"
 #include "gpu/command_buffer/service/shared_image_representation.h"
-#include "gpu/command_buffer/service/skia_utils.h"
 #include "third_party/skia/include/core/SkPromiseImageTexture.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "third_party/skia/include/core/SkSurfaceProps.h"
@@ -48,7 +47,7 @@
 
   void Destroy() override {
     DCHECK(backend_texture_.isValid());
-    DeleteGrBackendTexture(context_state_, &backend_texture_);
+    context_state_->gr_context()->deleteBackendTexture(backend_texture_);
   }
 
   bool IsCleared() const override { return cleared_; }
diff --git a/gpu/vulkan/vulkan_command_buffer.cc b/gpu/vulkan/vulkan_command_buffer.cc
index 4f14c85..4b11868 100644
--- a/gpu/vulkan/vulkan_command_buffer.cc
+++ b/gpu/vulkan/vulkan_command_buffer.cc
@@ -13,7 +13,9 @@
 
 namespace {
 
-VkPipelineStageFlags GetPipelineStageFlags(const VkImageLayout layout) {
+VkPipelineStageFlags GetPipelineStageFlags(
+    const VulkanDeviceQueue* device_queue,
+    const VkImageLayout layout) {
   switch (layout) {
     case VK_IMAGE_LAYOUT_UNDEFINED:
       return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
@@ -26,12 +28,18 @@
       return VK_PIPELINE_STAGE_TRANSFER_BIT;
     case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
       return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-    case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
-      return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
-             VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT |
-             VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT |
-             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
-             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
+    case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: {
+      VkPipelineStageFlags flags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
+                                   VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
+      if (device_queue->enabled_device_features().tessellationShader) {
+        flags |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
+                 VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
+      }
+      if (device_queue->enabled_device_features().geometryShader) {
+        flags |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
+      }
+      return flags;
+    }
     case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
       return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
     default:
@@ -221,9 +229,10 @@
   barrier.subresourceRange.levelCount = 1;
   barrier.subresourceRange.baseArrayLayer = 0;
   barrier.subresourceRange.layerCount = 1;
-  vkCmdPipelineBarrier(command_buffer_, GetPipelineStageFlags(old_layout),
-                       GetPipelineStageFlags(new_layout), 0, 0, nullptr, 0,
-                       nullptr, 1, &barrier);
+  vkCmdPipelineBarrier(command_buffer_,
+                       GetPipelineStageFlags(device_queue_, old_layout),
+                       GetPipelineStageFlags(device_queue_, new_layout), 0, 0,
+                       nullptr, 0, nullptr, 1, &barrier);
 }
 
 void VulkanCommandBuffer::CopyBufferToImage(VkBuffer buffer,
diff --git a/gpu/vulkan/vulkan_device_queue.h b/gpu/vulkan/vulkan_device_queue.h
index df3a0b0..0e769958 100644
--- a/gpu/vulkan/vulkan_device_queue.h
+++ b/gpu/vulkan/vulkan_device_queue.h
@@ -85,6 +85,10 @@
     return enabled_device_features_2_;
   }
 
+  const VkPhysicalDeviceFeatures& enabled_device_features() const {
+    return enabled_device_features_2_.features;
+  }
+
  private:
   gfx::ExtensionSet enabled_extensions_;
   VkPhysicalDevice vk_physical_device_ = VK_NULL_HANDLE;
diff --git a/gpu/vulkan/vulkan_instance.cc b/gpu/vulkan/vulkan_instance.cc
index 5d4b7d4..be186b4 100644
--- a/gpu/vulkan/vulkan_instance.cc
+++ b/gpu/vulkan/vulkan_instance.cc
@@ -4,8 +4,8 @@
 
 #include "gpu/vulkan/vulkan_instance.h"
 
-#include <unordered_set>
 #include <vector>
+
 #include "base/logging.h"
 #include "base/macros.h"
 #include "build/build_config.h"
@@ -83,10 +83,7 @@
   app_info.pApplicationName = "Chromium";
   app_info.apiVersion = api_version_;
 
-  std::vector<const char*> enabled_extensions;
-  enabled_extensions.insert(std::end(enabled_extensions),
-                            std::begin(required_extensions),
-                            std::end(required_extensions));
+  std::vector<const char*> enabled_extensions = required_extensions;
 
   uint32_t num_instance_exts = 0;
   result = vkEnumerateInstanceExtensionProperties(nullptr, &num_instance_exts,
@@ -131,7 +128,7 @@
   }
 #endif
 
-  std::vector<const char*> enabled_layer_names;
+  std::vector<const char*> enabled_layer_names = required_layers;
 #if DCHECK_IS_ON()
   uint32_t num_instance_layers = 0;
   result = vkEnumerateInstanceLayerProperties(&num_instance_layers, nullptr);
@@ -149,30 +146,34 @@
     return false;
   }
 
-  std::unordered_set<std::string> desired_layers({
-#if !defined(USE_X11) && !defined(USE_OZONE)
-    // TODO(crbug.com/843346): Make validation work in combination with
-    // VK_KHR_xlib_surface or switch to VK_KHR_xcb_surface.
-    "VK_LAYER_LUNARG_standard_validation",
-#endif
-  });
-
-  for (const VkLayerProperties& layer_property : instance_layers) {
-    if (desired_layers.find(layer_property.layerName) != desired_layers.end())
-      enabled_layer_names.push_back(layer_property.layerName);
+  // TODO(crbug.com/843346): Make validation work in combination with
+  // VK_KHR_xlib_surface or switch to VK_KHR_xcb_surface.
+  const base::StringPiece xlib_surface_extension_name("VK_KHR_xlib_surface");
+  bool enable_validation =
+      std::find_if(enabled_extensions.begin(), enabled_extensions.end(),
+                   [xlib_surface_extension_name](const char* e) {
+                     return xlib_surface_extension_name == e;
+                   }) == enabled_extensions.end();
+  if (enable_validation) {
+    constexpr base::StringPiece standard_validation(
+        "VK_LAYER_LUNARG_standard_validation");
+    for (const VkLayerProperties& layer_property : instance_layers) {
+      if (standard_validation == layer_property.layerName)
+        enabled_layer_names.push_back(standard_validation.data());
+    }
   }
-#endif
-  enabled_layer_names.insert(std::end(enabled_layer_names),
-                             std::begin(required_layers),
-                             std::end(required_layers));
+#endif  // DCHECK_IS_ON()
 
-  VkInstanceCreateInfo instance_create_info = {};
-  instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
-  instance_create_info.pApplicationInfo = &app_info;
-  instance_create_info.enabledLayerCount = enabled_layer_names.size();
-  instance_create_info.ppEnabledLayerNames = enabled_layer_names.data();
-  instance_create_info.enabledExtensionCount = enabled_extensions.size();
-  instance_create_info.ppEnabledExtensionNames = enabled_extensions.data();
+  VkInstanceCreateInfo instance_create_info = {
+      VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,  // sType
+      nullptr,                                 // pNext
+      0,                                       // flags
+      &app_info,                               // pApplicationInfo
+      enabled_layer_names.size(),              // enableLayerCount
+      enabled_layer_names.data(),              // ppEnabledLayerNames
+      enabled_extensions.size(),               // enabledExtensionCount
+      enabled_extensions.data(),               // ppEnabledExtensionNames
+  };
 
   result = vkCreateInstance(&instance_create_info, nullptr, &vk_instance_);
   if (VK_SUCCESS != result) {
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index a02ac3d2..ccb17aa 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -1331,6 +1331,8 @@
     builders {
       name: "chromeos-amd64-generic-cfi-thin-lto-rel"
       mixins: "chromeos-ci"
+      mixins: "linux-xenial"
+      mixins: "builderless"
     }
 
     builders {
@@ -1364,11 +1366,15 @@
       name: "chromeos-kevin-rel-hw-tests"
       mixins: "fyi-ci"
       mixins: "linux"
+      mixins: "linux-xenial"
+      mixins: "builderless"
     }
 
     builders {
       name: "chromeos-kevin-rel"
       mixins: "chromeos-ci"
+      mixins: "linux-xenial"
+      mixins: "builderless"
     }
 
     builders {
@@ -2557,8 +2563,9 @@
     }
     builders {
       name: "Linux ChromiumOS MSan Tests"
-      dimensions: "os:Ubuntu-14.04"
       mixins: "memory-ci"
+      mixins: "linux-xenial"
+      mixins: "builderless"
     }
     builders {
       name: "android-archive-dbg"
@@ -2657,8 +2664,9 @@
     }
     builders {
       name: "Linux Chromium OS ASan LSan Builder"
-      dimensions: "os:Ubuntu-14.04"
       mixins: "memory-ci"
+      mixins: "linux-xenial"
+      mixins: "builderless"
     }
     builders {
       name: "linux-annotator-rel"
@@ -2831,8 +2839,9 @@
     }
     builders {
       name: "Mojo ChromiumOS"
-      dimensions: "os:Ubuntu-14.04"
       mixins: "fyi-ci"
+      mixins: "linux-xenial"
+      mixins: "builderless"
     }
     builders {
       name: "Linux remote_run Builder"
@@ -2859,8 +2868,9 @@
     }
     builders {
       name: "Linux ChromiumOS MSan Builder"
-      dimensions: "os:Ubuntu-14.04"
       mixins: "memory-ci"
+      mixins: "linux-xenial"
+      mixins: "builderless"
     }
     builders {
       name: "Mojo Linux"
@@ -2870,8 +2880,9 @@
     }
     builders {
       name: "Linux Chromium OS ASan LSan Tests (1)"
-      dimensions: "os:Ubuntu-14.04"
       mixins: "memory-ci"
+      mixins: "linux-xenial"
+      mixins: "builderless"
     }
     builders {
       name: "Memory Infra Tester"
@@ -3638,8 +3649,9 @@
     builders {
       mixins: "android-try"
       mixins: "goma-rbe-prod"
+      mixins: "linux-xenial"
+      mixins: "builderless"
       name: "android_unswarmed_pixel_aosp"
-      dimensions: "os:Ubuntu-14.04"
     }
     builders {
       mixins: "android-optional-gpu-try"
@@ -3734,7 +3746,12 @@
       mixins: "builderless"
     }
 
-    builders { mixins: "chromeos-try" name: "chromeos-amd64-generic-cfi-thin-lto-rel" }
+    builders {
+      mixins: "chromeos-try"
+      name: "chromeos-amd64-generic-cfi-thin-lto-rel"
+      mixins: "linux-xenial"
+      mixins: "builderless"
+    }
     builders {
       mixins: "chromeos-try"
       mixins: "linux-xenial"
@@ -3747,8 +3764,18 @@
       mixins: "builderless"
       name: "chromeos-arm-generic-rel"
     }
-    builders { mixins: "chromeos-try" name: "chromeos-kevin-compile-rel" }
-    builders { mixins: "chromeos-try" name: "chromeos-kevin-rel" }
+    builders {
+      mixins: "chromeos-try"
+      name: "chromeos-kevin-compile-rel"
+      mixins: "linux-xenial"
+      mixins: "builderless"
+    }
+    builders {
+      mixins: "chromeos-try"
+      name: "chromeos-kevin-rel"
+      mixins: "linux-xenial"
+      mixins: "builderless"
+    }
     builders {
       mixins: "chromeos-try"
       mixins: "linux-xenial"
@@ -3965,11 +3992,15 @@
       mixins: "linux-try"
       mixins: "goma-j150"
       name: "linux_chromium_chromeos_asan_rel_ng"
+      mixins: "linux-xenial"
+      mixins: "builderless"
     }
     builders {
       mixins: "linux-try"
       mixins: "goma-j150"
       name: "linux_chromium_chromeos_msan_rel_ng"
+      mixins: "linux-xenial"
+      mixins: "builderless"
     }
     builders {
       name: "linux_chromium_clobber_deterministic",
@@ -4041,7 +4072,12 @@
       mixins: "goma-rbe-prod"
       name: "linux_mojo"
     }
-    builders { mixins: "linux-try" name: "linux_mojo_chromeos" }
+    builders {
+      mixins: "linux-try"
+      name: "linux_mojo_chromeos"
+      mixins: "linux-xenial"
+      mixins: "builderless"
+    }
     builders { mixins: "linux-optional-gpu-try" name: "linux_optional_gpu_tests_rel" }
     builders {
       mixins: "linux-try"
@@ -4337,8 +4373,9 @@
     }
     builders {
       name: "linux_android_dbg_ng"
-      dimensions: "os:Ubuntu-14.04"
       mixins: "android-try"
+      mixins: "linux-xenial"
+      mixins: "builderless"
     }
     builders {
       name: "android_compile_x64_dbg"
diff --git a/ios/chrome/app/application_delegate/BUILD.gn b/ios/chrome/app/application_delegate/BUILD.gn
index 518e2cd..ea798dd8 100644
--- a/ios/chrome/app/application_delegate/BUILD.gn
+++ b/ios/chrome/app/application_delegate/BUILD.gn
@@ -125,6 +125,7 @@
     "//ios/chrome/browser/net",
     "//ios/chrome/browser/payments",
     "//ios/chrome/browser/search_engines",
+    "//ios/chrome/browser/signin",
     "//ios/chrome/browser/tabs",
     "//ios/chrome/browser/u2f",
     "//ios/chrome/browser/ui/authentication",
diff --git a/ios/chrome/app/application_delegate/app_state.mm b/ios/chrome/app/application_delegate/app_state.mm
index 7360ad5..fa2edc2 100644
--- a/ios/chrome/app/application_delegate/app_state.mm
+++ b/ios/chrome/app/application_delegate/app_state.mm
@@ -38,6 +38,8 @@
 #import "ios/chrome/browser/metrics/ios_profile_session_durations_service.h"
 #import "ios/chrome/browser/metrics/ios_profile_session_durations_service_factory.h"
 #import "ios/chrome/browser/metrics/previous_session_info.h"
+#import "ios/chrome/browser/signin/authentication_service.h"
+#import "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller.h"
 #import "ios/chrome/browser/ui/browser_view/browser_view_controller.h"
@@ -52,7 +54,7 @@
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/distribution/app_distribution_provider.h"
 #import "ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h"
-#include "ios/web/public/web_task_traits.h"
+#include "ios/web/public/thread/web_task_traits.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 
@@ -170,6 +172,13 @@
   }
   _applicationInBackground = YES;
 
+  ios::ChromeBrowserState* browserState =
+      _browserLauncher.interfaceProvider.mainInterface.browserState;
+  if (browserState) {
+    AuthenticationServiceFactory::GetForBrowserState(browserState)
+        ->OnApplicationDidEnterBackground();
+  }
+
   breakpad_helper::SetCurrentlyInBackground(true);
 
   if ([_browserLauncher browserInitializationStage] <
@@ -275,6 +284,12 @@
     return;
 
   _applicationInBackground = NO;
+  ios::ChromeBrowserState* browserState =
+      _browserLauncher.interfaceProvider.mainInterface.browserState;
+  if (browserState) {
+    AuthenticationServiceFactory::GetForBrowserState(browserState)
+        ->OnApplicationWillEnterForeground();
+  }
 
   [_incognitoBlocker removeFromSuperview];
   _incognitoBlocker = nil;
diff --git a/ios/chrome/app/application_delegate/app_state_unittest.mm b/ios/chrome/app/application_delegate/app_state_unittest.mm
index 587f9a45..14ec0f7 100644
--- a/ios/chrome/app/application_delegate/app_state_unittest.mm
+++ b/ios/chrome/app/application_delegate/app_state_unittest.mm
@@ -50,7 +50,7 @@
 #include "ios/public/provider/chrome/browser/user_feedback/test_user_feedback_provider.h"
 #import "ios/testing/ocmock_complex_type_helper.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
-#include "ios/web/public/web_task_traits.h"
+#include "ios/web/public/thread/web_task_traits.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 #include "third_party/ocmock/gtest_support.h"
 
@@ -936,6 +936,7 @@
   BrowserInitializationStageType stage = INITIALIZATION_STAGE_BACKGROUND;
 
   [[[browserLauncher stub] andReturnValue:@(stage)] browserInitializationStage];
+  [[[browserLauncher stub] andReturn:nil] interfaceProvider];
 
   ASSERT_EQ(NSUInteger(0), [window subviews].count);
 
diff --git a/ios/chrome/app/application_delegate/metrics_mediator.mm b/ios/chrome/app/application_delegate/metrics_mediator.mm
index 1f62fad..41042f89 100644
--- a/ios/chrome/app/application_delegate/metrics_mediator.mm
+++ b/ios/chrome/app/application_delegate/metrics_mediator.mm
@@ -29,9 +29,9 @@
 #include "ios/chrome/common/app_group/app_group_metrics_mainapp.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/distribution/app_distribution_provider.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state/web_state.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 21c22bf..5122e1c 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -157,8 +157,8 @@
 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
 #import "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
+#include "ios/web/public/thread/web_task_traits.h"
 #import "ios/web/public/web_state/web_state.h"
-#include "ios/web/public/web_task_traits.h"
 #import "ios/web/public/web_view_creation_util.h"
 #include "ios/web/public/webui/web_ui_ios_controller_factory.h"
 #include "mojo/core/embedder/embedder.h"
diff --git a/ios/chrome/browser/application_context_impl.cc b/ios/chrome/browser/application_context_impl.cc
index 736c2fc..6e46fc65 100644
--- a/ios/chrome/browser/application_context_impl.cc
+++ b/ios/chrome/browser/application_context_impl.cc
@@ -51,8 +51,8 @@
 #include "ios/chrome/browser/prefs/ios_chrome_pref_service_factory.h"
 #include "ios/chrome/browser/update_client/ios_chrome_update_query_params_delegate.h"
 #include "ios/chrome/common/channel_info.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/log/net_log.h"
 #include "net/log/net_log_capture_mode.h"
 #include "net/socket/client_socket_pool_manager.h"
diff --git a/ios/chrome/browser/bookmarks/bookmark_model_factory.cc b/ios/chrome/browser/bookmarks/bookmark_model_factory.cc
index 7560702..ffecba03 100644
--- a/ios/chrome/browser/bookmarks/bookmark_model_factory.cc
+++ b/ios/chrome/browser/bookmarks/bookmark_model_factory.cc
@@ -20,8 +20,8 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
 #include "ios/chrome/browser/undo/bookmark_undo_service_factory.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 
 namespace ios {
 
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state.mm b/ios/chrome/browser/browser_state/chrome_browser_state.mm
index 385f72d..f6e8cde6 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state.mm
+++ b/ios/chrome/browser/browser_state/chrome_browser_state.mm
@@ -13,8 +13,8 @@
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "components/variations/net/variations_http_headers.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state/web_state.h"
-#include "ios/web/public/web_thread.h"
 #include "ios/web/public/webui/web_ui_ios.h"
 #include "ios/web/webui/url_data_manager_ios_backend.h"
 #include "net/url_request/url_request_context_getter.h"
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc b/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc
index 055daa4..9dda9484 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc
@@ -33,7 +33,7 @@
 #include "ios/chrome/browser/prefs/ios_chrome_pref_service_factory.h"
 #include "ios/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_factory.h"
 #include "ios/chrome/browser/signin/identity_service_creator.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "services/identity/public/mojom/constants.mojom.h"
 
 namespace {
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm b/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm
index a6744ce1..a407426 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm
@@ -31,8 +31,8 @@
 #import "ios/net/cookies/cookie_store_ios.h"
 #import "ios/net/cookies/ns_http_system_cookie_store.h"
 #import "ios/net/cookies/system_cookie_store.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/base/cache_type.h"
 #include "net/cookies/cookie_store.h"
 #include "net/http/http_cache.h"
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm
index e472186c..3d246d4 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm
@@ -44,8 +44,8 @@
 #include "ios/chrome/browser/net/ios_chrome_url_request_context_getter.h"
 #import "ios/net/cookies/system_cookie_store.h"
 #include "ios/web/public/browsing_data/system_cookie_store_util.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/cert/cert_verifier.h"
 #include "net/cert/multi_log_ct_verifier.h"
 #include "net/cookies/canonical_cookie.h"
diff --git a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc
index 3ed3847..123babf1 100644
--- a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc
+++ b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc
@@ -14,8 +14,8 @@
 #include "components/user_prefs/user_prefs.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/net/ios_chrome_url_request_context_getter.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 
 OffTheRecordChromeBrowserStateImpl::OffTheRecordChromeBrowserStateImpl(
     scoped_refptr<base::SequencedTaskRunner> io_task_runner,
diff --git a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_io_data.mm b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_io_data.mm
index 54809b26..e8a20c1 100644
--- a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_io_data.mm
+++ b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_io_data.mm
@@ -24,8 +24,8 @@
 #include "ios/chrome/browser/net/ios_chrome_url_request_context_getter.h"
 #include "ios/chrome/browser/pref_names.h"
 #import "ios/net/cookies/system_cookie_store.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/cookies/cookie_store.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/ftp/ftp_network_layer.h"
diff --git a/ios/chrome/browser/browser_state/test_chrome_browser_state.mm b/ios/chrome/browser/browser_state/test_chrome_browser_state.mm
index bc9f7eeb..152a185 100644
--- a/ios/chrome/browser/browser_state/test_chrome_browser_state.mm
+++ b/ios/chrome/browser/browser_state/test_chrome_browser_state.mm
@@ -47,8 +47,8 @@
 #include "ios/chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "ios/chrome/browser/web_data_service_factory.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/url_request/url_request_test_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm b/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
index 3303fd02e..3ffc0265d 100644
--- a/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
+++ b/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
@@ -60,8 +60,8 @@
 #include "ios/chrome/browser/web_data_service_factory.h"
 #include "ios/net/http_cache_helper.h"
 #import "ios/web/public/browsing_data/browsing_data_removing_util.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_view_creation_util.h"
 #import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
 #include "net/base/net_errors.h"
diff --git a/ios/chrome/browser/browsing_data/cache_counter.cc b/ios/chrome/browser/browsing_data/cache_counter.cc
index 05ef844..1b4d67e 100644
--- a/ios/chrome/browser/browsing_data/cache_counter.cc
+++ b/ios/chrome/browser/browsing_data/cache_counter.cc
@@ -8,8 +8,8 @@
 #include "components/browsing_data/core/pref_names.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/web/public/browser_state.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/base/completion_repeating_callback.h"
 #include "net/base/net_errors.h"
 #include "net/disk_cache/disk_cache.h"
diff --git a/ios/chrome/browser/browsing_data/cache_counter_unittest.cc b/ios/chrome/browser/browsing_data/cache_counter_unittest.cc
index f0822b7d..9b52873d 100644
--- a/ios/chrome/browser/browsing_data/cache_counter_unittest.cc
+++ b/ios/chrome/browser/browsing_data/cache_counter_unittest.cc
@@ -21,8 +21,8 @@
 #include "components/prefs/testing_pref_service.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/http/http_cache.h"
 #include "net/http/http_transaction_factory.h"
diff --git a/ios/chrome/browser/crash_report/crash_report_helper.mm b/ios/chrome/browser/crash_report/crash_report_helper.mm
index 7688f518..b0b52ee 100644
--- a/ios/chrome/browser/crash_report/crash_report_helper.mm
+++ b/ios/chrome/browser/crash_report/crash_report_helper.mm
@@ -26,10 +26,10 @@
 #include "ios/web/public/browser_state.h"
 #import "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
-#include "ios/web/public/web_thread.h"
 #import "net/base/mac/url_conversions.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc b/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
index 4f65c115..6a43bc0 100644
--- a/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
+++ b/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
@@ -21,7 +21,7 @@
 #include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/web/public/browser_state.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace {
diff --git a/ios/chrome/browser/external_files/external_file_remover_impl.mm b/ios/chrome/browser/external_files/external_file_remover_impl.mm
index 2622c3c..0d64f51 100644
--- a/ios/chrome/browser/external_files/external_file_remover_impl.mm
+++ b/ios/chrome/browser/external_files/external_file_remover_impl.mm
@@ -21,8 +21,8 @@
 #import "ios/chrome/browser/tabs/tab_model_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "ios/web/public/navigation_item.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state/web_state.h"
-#include "ios/web/public/web_thread.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.cc b/ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.cc
index 10ed50fc..5f0c50334 100644
--- a/ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.cc
+++ b/ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.cc
@@ -17,8 +17,8 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
 #include "ios/chrome/common/channel_info.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
 
diff --git a/ios/chrome/browser/history/top_sites_factory.cc b/ios/chrome/browser/history/top_sites_factory.cc
index 4917329..e190d7a 100644
--- a/ios/chrome/browser/history/top_sites_factory.cc
+++ b/ios/chrome/browser/history/top_sites_factory.cc
@@ -17,7 +17,7 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
 #include "ios/chrome/browser/history/history_utils.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 
 namespace ios {
 
diff --git a/ios/chrome/browser/installation_notifier.mm b/ios/chrome/browser/installation_notifier.mm
index 701aa62..6c08994 100644
--- a/ios/chrome/browser/installation_notifier.mm
+++ b/ios/chrome/browser/installation_notifier.mm
@@ -11,7 +11,7 @@
 
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/base/backoff_entry.h"
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.mm b/ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.mm
index 75f44e7..08cc3ea 100644
--- a/ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.mm
+++ b/ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.mm
@@ -23,8 +23,8 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.h"
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
+#include "ios/web/public/thread/web_task_traits.h"
 #include "ios/web/public/web_client.h"
-#include "ios/web/public/web_task_traits.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ios_chrome_main_parts.mm b/ios/chrome/browser/ios_chrome_main_parts.mm
index 1d5c33b..d41dcda7 100644
--- a/ios/chrome/browser/ios_chrome_main_parts.mm
+++ b/ios/chrome/browser/ios_chrome_main_parts.mm
@@ -46,8 +46,8 @@
 #include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/translate/translate_service_ios.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/base/network_change_notifier.h"
 #include "net/http/http_network_layer.h"
 #include "net/http/http_stream_factory.h"
diff --git a/ios/chrome/browser/metrics/first_user_action_recorder.cc b/ios/chrome/browser/metrics/first_user_action_recorder.cc
index e84a4831..4033efe 100644
--- a/ios/chrome/browser/metrics/first_user_action_recorder.cc
+++ b/ios/chrome/browser/metrics/first_user_action_recorder.cc
@@ -12,7 +12,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 
 const char* kFirstUserActionNewTaskHistogramName[] = {
     "FirstUserAction.BackgroundTimeNewTaskHandset",
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
index 422dd286..9299937a 100644
--- a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
+++ b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
@@ -61,7 +61,7 @@
 #include "ios/chrome/browser/tab_parenting_global_observer.h"
 #include "ios/chrome/browser/translate/translate_ranker_metrics_provider.h"
 #include "ios/chrome/common/channel_info.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/net/chrome_cookie_store_ios_client.mm b/ios/chrome/browser/net/chrome_cookie_store_ios_client.mm
index dd98300d..a644690 100644
--- a/ios/chrome/browser/net/chrome_cookie_store_ios_client.mm
+++ b/ios/chrome/browser/net/chrome_cookie_store_ios_client.mm
@@ -5,8 +5,8 @@
 #include "ios/chrome/browser/net/chrome_cookie_store_ios_client.h"
 
 #include "base/task/post_task.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/net/cookie_util.mm b/ios/chrome/browser/net/cookie_util.mm
index a56a9d55..e899d4c 100644
--- a/ios/chrome/browser/net/cookie_util.mm
+++ b/ios/chrome/browser/net/cookie_util.mm
@@ -18,8 +18,8 @@
 #include "ios/net/cookies/cookie_store_ios_persistent.h"
 #import "ios/net/cookies/system_cookie_store.h"
 #include "ios/web/common/features.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/cookies/cookie_monster.h"
 #include "net/cookies/cookie_store.h"
 #include "net/extras/sqlite/sqlite_persistent_cookie_store.h"
diff --git a/ios/chrome/browser/net/http_server_properties_manager_factory.cc b/ios/chrome/browser/net/http_server_properties_manager_factory.cc
index 2e7ed4c..84b3dde 100644
--- a/ios/chrome/browser/net/http_server_properties_manager_factory.cc
+++ b/ios/chrome/browser/net/http_server_properties_manager_factory.cc
@@ -10,7 +10,7 @@
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/json_pref_store.h"
 #include "ios/chrome/browser/pref_names.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/http/http_server_properties_manager.h"
 
 namespace {
diff --git a/ios/chrome/browser/net/ios_chrome_http_user_agent_settings.mm b/ios/chrome/browser/net/ios_chrome_http_user_agent_settings.mm
index 6262bb0..a6bae224 100644
--- a/ios/chrome/browser/net/ios_chrome_http_user_agent_settings.mm
+++ b/ios/chrome/browser/net/ios_chrome_http_user_agent_settings.mm
@@ -7,9 +7,9 @@
 #include "base/task/post_task.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/prefs/pref_service.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/web_client.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
 #include "net/http/http_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/net/ios_chrome_network_delegate.cc b/ios/chrome/browser/net/ios_chrome_network_delegate.cc
index e07451ec..d55b59d 100644
--- a/ios/chrome/browser/net/ios_chrome_network_delegate.cc
+++ b/ios/chrome/browser/net/ios_chrome_network_delegate.cc
@@ -18,8 +18,8 @@
 #include "components/prefs/pref_member.h"
 #include "components/prefs/pref_service.h"
 #include "ios/chrome/browser/pref_names.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
 #include "net/cookies/cookie_options.h"
diff --git a/ios/chrome/browser/net/ios_chrome_url_request_context_getter.cc b/ios/chrome/browser/net/ios_chrome_url_request_context_getter.cc
index c895298d..916daf3 100644
--- a/ios/chrome/browser/net/ios_chrome_url_request_context_getter.cc
+++ b/ios/chrome/browser/net/ios_chrome_url_request_context_getter.cc
@@ -10,8 +10,8 @@
 #include "base/task/post_task.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state_io_data.h"
 #include "ios/chrome/browser/ios_chrome_io_thread.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/cookies/cookie_store.h"
 
 class IOSChromeURLRequestContextFactory {
diff --git a/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc b/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc
index 05d203c..73418f18 100644
--- a/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc
+++ b/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc
@@ -11,7 +11,7 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/json_parser/in_process_json_parser.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 
diff --git a/ios/chrome/browser/omaha/omaha_service.mm b/ios/chrome/browser/omaha/omaha_service.mm
index a8b2463..07fd502 100644
--- a/ios/chrome/browser/omaha/omaha_service.mm
+++ b/ios/chrome/browser/omaha/omaha_service.mm
@@ -36,8 +36,8 @@
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/omaha/omaha_service_provider.h"
 #include "ios/public/provider/chrome/browser/omaha/omaha_xml_writer.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "libxml/xmlwriter.h"
 #include "net/base/backoff_entry.h"
 #include "net/base/load_flags.h"
diff --git a/ios/chrome/browser/omaha/omaha_service_unittest.mm b/ios/chrome/browser/omaha/omaha_service_unittest.mm
index ab59a53..737f355d 100644
--- a/ios/chrome/browser/omaha/omaha_service_unittest.mm
+++ b/ios/chrome/browser/omaha/omaha_service_unittest.mm
@@ -23,7 +23,7 @@
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/omaha/omaha_service_provider.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/http/http_status_code.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
diff --git a/ios/chrome/browser/prerender/preload_controller.mm b/ios/chrome/browser/prerender/preload_controller.mm
index 973b8131..04f5eb0 100644
--- a/ios/chrome/browser/prerender/preload_controller.mm
+++ b/ios/chrome/browser/prerender/preload_controller.mm
@@ -31,10 +31,10 @@
 #import "ios/web/public/deprecated/crw_native_content_holder.h"
 #import "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ios/web/public/web_state/web_state_observer_bridge.h"
 #import "ios/web/public/web_state/web_state_policy_decider_bridge.h"
-#include "ios/web/public/web_thread.h"
 #import "ios/web/web_state/ui/crw_web_controller.h"
 #import "net/base/mac/url_conversions.h"
 #include "ui/base/page_transition_types.h"
diff --git a/ios/chrome/browser/reading_list/offline_page_tab_helper.mm b/ios/chrome/browser/reading_list/offline_page_tab_helper.mm
index 0d7ea86..3726d020 100644
--- a/ios/chrome/browser/reading_list/offline_page_tab_helper.mm
+++ b/ios/chrome/browser/reading_list/offline_page_tab_helper.mm
@@ -22,9 +22,9 @@
 #include "ios/chrome/browser/reading_list/reading_list_download_service.h"
 #include "ios/chrome/browser/reading_list/reading_list_download_service_factory.h"
 #import "ios/web/public/navigation_manager.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state/navigation_context.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
 #include "ui/base/page_transition_types.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/reading_list/reading_list_model_factory.cc b/ios/chrome/browser/reading_list/reading_list_model_factory.cc
index 1f9c444..19efe9d1 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_factory.cc
+++ b/ios/chrome/browser/reading_list/reading_list_model_factory.cc
@@ -23,7 +23,7 @@
 #include "ios/chrome/browser/sync/model_type_store_service_factory.h"
 #include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/common/channel_info.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 
 // static
 ReadingListModel* ReadingListModelFactory::GetForBrowserState(
diff --git a/ios/chrome/browser/rlz/rlz_tracker_delegate_impl.cc b/ios/chrome/browser/rlz/rlz_tracker_delegate_impl.cc
index 447f542..34feaa67 100644
--- a/ios/chrome/browser/rlz/rlz_tracker_delegate_impl.cc
+++ b/ios/chrome/browser/rlz/rlz_tracker_delegate_impl.cc
@@ -15,7 +15,7 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/google/google_brand.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 RLZTrackerDelegateImpl::RLZTrackerDelegateImpl() {}
diff --git a/ios/chrome/browser/search_engines/search_engine_tab_helper.mm b/ios/chrome/browser/search_engines/search_engine_tab_helper.mm
index fb5cf23d..8c5911bf 100644
--- a/ios/chrome/browser/search_engines/search_engine_tab_helper.mm
+++ b/ios/chrome/browser/search_engines/search_engine_tab_helper.mm
@@ -12,7 +12,7 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/search_engines/template_url_fetcher_factory.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
-#include "ios/web/public/favicon_status.h"
+#include "ios/web/public/favicon/favicon_status.h"
 #import "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
 #import "ios/web/public/web_state/navigation_context.h"
diff --git a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc
index 7ee2a1c7..539f065b 100644
--- a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc
+++ b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc
@@ -15,7 +15,7 @@
 #include "ios/chrome/browser/google/google_url_tracker_factory.h"
 #include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/common/channel_info.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/base/escape.h"
 #include "rlz/buildflags/buildflags.h"
 #include "url/gurl.h"
diff --git a/ios/chrome/browser/share_extension/share_extension_item_receiver.mm b/ios/chrome/browser/share_extension/share_extension_item_receiver.mm
index ece6bfb..2aeb855 100644
--- a/ios/chrome/browser/share_extension/share_extension_item_receiver.mm
+++ b/ios/chrome/browser/share_extension/share_extension_item_receiver.mm
@@ -21,8 +21,8 @@
 #include "components/reading_list/core/reading_list_model_observer.h"
 #include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/common/app_group/app_group_constants.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "net/base/mac/url_conversions.h"
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/signin/authentication_service.h b/ios/chrome/browser/signin/authentication_service.h
index c6fc25b..b03fc85 100644
--- a/ios/chrome/browser/signin/authentication_service.h
+++ b/ios/chrome/browser/signin/authentication_service.h
@@ -60,30 +60,30 @@
   void ResetPromptForSignIn();
 
   // Returns whether user should be prompted to Sign in to Chrome.
-  bool ShouldPromptForSignIn();
+  bool ShouldPromptForSignIn() const;
 
   // Returns whether the token service accounts have changed since the last time
   // they were stored in the browser state prefs. This storing happens every
   // time the accounts change in foreground.
   // This reloads the cached accounts if the information might be stale.
-  virtual bool HaveAccountsChanged();
+  virtual bool HaveAccountsChanged() const;
 
   // ChromeIdentity management
 
   // Returns true if the user is signed in.
   // While the AuthenticationService is in background, this will reload the
   // credentials to ensure the value is up to date.
-  virtual bool IsAuthenticated();
+  virtual bool IsAuthenticated() const;
 
   // Returns true if the user is signed in and the identity is considered
   // managed.
-  virtual bool IsAuthenticatedIdentityManaged();
+  virtual bool IsAuthenticatedIdentityManaged() const;
 
   // Retrieves the identity of the currently authenticated user or |nil| if
   // either the user is not authenticated, or is authenticated through
   // ClientLogin.
   // Virtual for testing.
-  virtual ChromeIdentity* GetAuthenticatedIdentity();
+  virtual ChromeIdentity* GetAuthenticatedIdentity() const;
 
   // Signs |identity| in to Chrome with |hosted_domain| as its hosted domain,
   // pauses sync and logs |identity| in to http://google.com. If |identity| has
@@ -98,7 +98,7 @@
                        ProceduralBlock completion);
 
   // Returns whether there is a cached associated MDM error for |identity|.
-  bool HasCachedMDMErrorForIdentity(ChromeIdentity* identity);
+  bool HasCachedMDMErrorForIdentity(ChromeIdentity* identity) const;
 
   // Shows the MDM Error dialog for |identity| if it has an associated MDM
   // error. Returns true if |identity| had an associated error, false otherwise.
@@ -112,16 +112,18 @@
   // Returns a weak pointer of this.
   base::WeakPtr<AuthenticationService> GetWeakPtr();
 
+  // This needs to be invoked when the application enters foreground to
+  // sync the accounts between the IdentityManager and the SSO library.
+  void OnApplicationWillEnterForeground();
+
+  // This needs to be invoked when the application enters background to
+  // sync the accounts between the IdentityManager and the SSO library.
+  void OnApplicationDidEnterBackground();
+
  private:
   friend class AuthenticationServiceTest;
   friend class AuthenticationServiceFake;
 
-  // Method called each time the application enters foreground.
-  void OnApplicationEnterForeground();
-
-  // Method called each time the application enters background.
-  void OnApplicationEnterBackground();
-
   // Migrates the token service accounts stored in prefs from emails to account
   // ids.
   void MigrateAccountsStoredInPrefsIfNeeded();
@@ -134,7 +136,7 @@
 
   // Returns the cached MDM infos associated with |identity|. If the cache is
   // stale for |identity|, the entry might be removed.
-  NSDictionary* GetCachedMDMInfo(ChromeIdentity* identity);
+  NSDictionary* GetCachedMDMInfo(ChromeIdentity* identity) const;
 
   // Handles an MDM notification |user_info| associated with |identity|.
   // Returns whether the notification associated with |user_info| was fully
@@ -172,7 +174,9 @@
 
   // Computes whether the available accounts have changed since the last time
   // they were stored in the  browser state prefs.
-  void ComputeHaveAccountsChanged();
+  // |should_prompt| indicates whether the user should be prompted if the
+  // authenticated identity was removed.
+  void ComputeHaveAccountsChanged(bool should_prompt);
 
   // identity::IdentityManager::Observer implementation.
   void OnEndBatchOfRefreshTokenStateChanges() override;
@@ -202,25 +206,20 @@
   // cannot be trusted.
   bool have_accounts_changed_ = false;
 
-  // Whether the AuthenticationService behaves as being in foreground. In
-  // background, identities changes aren't always notified and can't be
-  // initiated by the user.
-  bool is_in_foreground_ = false;
-
   // Whether the AuthenticationService is currently reloading credentials, used
   // to avoid an infinite reloading loop.
   bool is_reloading_credentials_ = false;
 
   // Map between account IDs and their associated MDM error.
-  std::map<std::string, NSDictionary*> cached_mdm_infos_;
-
-  id foreground_observer_ = nil;
-  id background_observer_ = nil;
+  mutable std::map<std::string, NSDictionary*> cached_mdm_infos_;
 
   ScopedObserver<ios::ChromeIdentityService,
                  ios::ChromeIdentityService::Observer>
       identity_service_observer_;
 
+  ScopedObserver<identity::IdentityManager, identity::IdentityManager::Observer>
+      identity_manager_observer_;
+
   base::WeakPtrFactory<AuthenticationService> weak_pointer_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AuthenticationService);
diff --git a/ios/chrome/browser/signin/authentication_service.mm b/ios/chrome/browser/signin/authentication_service.mm
index 7f7cd78d..b049ba5c 100644
--- a/ios/chrome/browser/signin/authentication_service.mm
+++ b/ios/chrome/browser/signin/authentication_service.mm
@@ -4,8 +4,6 @@
 
 #import "ios/chrome/browser/signin/authentication_service.h"
 
-#import <UIKit/UIKit.h>
-
 #include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/location.h"
@@ -80,12 +78,12 @@
       identity_manager_(identity_manager),
       sync_service_(sync_service),
       identity_service_observer_(this),
+      identity_manager_observer_(this),
       weak_pointer_factory_(this) {
   DCHECK(pref_service_);
   DCHECK(sync_setup_service_);
   DCHECK(identity_manager_);
   DCHECK(sync_service_);
-  identity_manager_->AddObserver(this);
 }
 
 AuthenticationService::~AuthenticationService() {
@@ -123,54 +121,28 @@
   }
   breakpad_helper::SetCurrentlySignedIn(is_signed_in);
 
-  OnApplicationEnterForeground();
-
-  NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
-  foreground_observer_ =
-      [center addObserverForName:UIApplicationWillEnterForegroundNotification
-                          object:nil
-                           queue:nil
-                      usingBlock:^(NSNotification* notification) {
-                        OnApplicationEnterForeground();
-                      }];
-  background_observer_ =
-      [center addObserverForName:UIApplicationDidEnterBackgroundNotification
-                          object:nil
-                           queue:nil
-                      usingBlock:^(NSNotification* notification) {
-                        OnApplicationEnterBackground();
-                      }];
-
   identity_service_observer_.Add(
       ios::GetChromeBrowserProvider()->GetChromeIdentityService());
+
+  OnApplicationWillEnterForeground();
 }
 
 void AuthenticationService::Shutdown() {
-  identity_manager_->RemoveObserver(this);
-
-  NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
-  [center removeObserver:foreground_observer_];
-  [center removeObserver:background_observer_];
-
+  identity_manager_observer_.RemoveAll();
   delegate_.reset();
 }
 
-void AuthenticationService::OnApplicationEnterForeground() {
-  if (is_in_foreground_) {
+void AuthenticationService::OnApplicationWillEnterForeground() {
+  if (identity_manager_observer_.IsObservingSources())
     return;
-  }
+
+  identity_manager_observer_.Add(identity_manager_);
 
   // As the SSO library does not send notification when the app is in the
   // background, reload the credentials and check whether any accounts have
   // changed (both are done by calling ComputeHaveAccountsChanged). After
   // that, save the current list of accounts.
-  ComputeHaveAccountsChanged();
-  StoreAccountsInPrefs();
-
-  // Set |is_in_foreground_| only after handling forgotten identity.
-  // This ensures that any changes made to the SSOAuth identities before this
-  // are correctly seen as made while in background.
-  is_in_foreground_ = true;
+  ComputeHaveAccountsChanged(/*should_prompt=*/true);
 
   if (IsAuthenticated()) {
     bool sync_enabled = sync_setup_service_->IsSyncEnabled();
@@ -196,8 +168,14 @@
   }
 }
 
-void AuthenticationService::OnApplicationEnterBackground() {
-  is_in_foreground_ = false;
+void AuthenticationService::OnApplicationDidEnterBackground() {
+  if (!identity_manager_observer_.IsObservingSources())
+    return;
+
+  // Stop observing |identity_manager_| when in the background. Note that
+  // this allows checking whether the app is in background without having a
+  // separate bool by using identity_manager_observer_.IsObservingSources().
+  identity_manager_observer_.Remove(identity_manager_);
 }
 
 void AuthenticationService::SetPromptForSignIn() {
@@ -208,33 +186,32 @@
   pref_service_->SetBoolean(prefs::kSigninShouldPromptForSigninAgain, false);
 }
 
-bool AuthenticationService::ShouldPromptForSignIn() {
+bool AuthenticationService::ShouldPromptForSignIn() const {
   return pref_service_->GetBoolean(prefs::kSigninShouldPromptForSigninAgain);
 }
 
-void AuthenticationService::ComputeHaveAccountsChanged() {
+void AuthenticationService::ComputeHaveAccountsChanged(bool should_prompt) {
+  // Load accounts from preference before synchronizing the accounts with
+  // the system, otherwiser we would never detect any changes to the list
+  // of accounts.
+  std::vector<std::string> old_accounts = GetAccountsInPrefs();
+  std::sort(old_accounts.begin(), old_accounts.end());
+
   // Reload credentials to ensure the accounts from the token service are
   // up-to-date.
-  // While the AuthenticationService is in background, changes should be shown
-  // to the user and |should_prompt| is true.
-  ReloadCredentialsFromIdentities(!is_in_foreground_ /* should_prompt */);
+  ReloadCredentialsFromIdentities(should_prompt);
+
   std::vector<CoreAccountInfo> new_accounts_info =
       identity_manager_->GetAccountsWithRefreshTokens();
   std::vector<std::string> new_accounts;
   for (const CoreAccountInfo& account_info : new_accounts_info)
     new_accounts.push_back(account_info.account_id);
-  std::vector<std::string> old_accounts = GetAccountsInPrefs();
   std::sort(new_accounts.begin(), new_accounts.end());
-  std::sort(old_accounts.begin(), old_accounts.end());
+
   have_accounts_changed_ = old_accounts != new_accounts;
 }
 
-bool AuthenticationService::HaveAccountsChanged() {
-  if (!is_in_foreground_) {
-    // While AuthenticationService is in background, the value can change
-    // without warning and needs to be recomputed every time.
-    ComputeHaveAccountsChanged();
-  }
+bool AuthenticationService::HaveAccountsChanged() const {
   return have_accounts_changed_;
 }
 
@@ -292,7 +269,7 @@
   return accounts;
 }
 
-ChromeIdentity* AuthenticationService::GetAuthenticatedIdentity() {
+ChromeIdentity* AuthenticationService::GetAuthenticatedIdentity() const {
   // There is no authenticated identity if there is no signed in user or if the
   // user signed in via the client login flow.
   if (!IsAuthenticated())
@@ -386,7 +363,7 @@
 }
 
 NSDictionary* AuthenticationService::GetCachedMDMInfo(
-    ChromeIdentity* identity) {
+    ChromeIdentity* identity) const {
   auto it = cached_mdm_infos_.find(
       ChromeIdentityToAccountID(identity_manager_, identity));
 
@@ -405,7 +382,7 @@
 }
 
 bool AuthenticationService::HasCachedMDMErrorForIdentity(
-    ChromeIdentity* identity) {
+    ChromeIdentity* identity) const {
   return GetCachedMDMInfo(identity) != nil;
 }
 
@@ -434,12 +411,10 @@
 }
 
 void AuthenticationService::OnEndBatchOfRefreshTokenStateChanges() {
-  if (is_in_foreground_) {
-    // Accounts maybe have been excluded or included from the current browser
-    // state, without any change to the identity list.
-    // Store the current list of accounts to make sure it is up-to-date.
-    StoreAccountsInPrefs();
-  }
+  // Accounts maybe have been excluded or included from the current browser
+  // state, without any change to the identity list.
+  // Store the current list of accounts to make sure it is up-to-date.
+  StoreAccountsInPrefs();
 }
 
 void AuthenticationService::OnIdentityListChanged() {
@@ -452,7 +427,8 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&AuthenticationService::HandleIdentityListChanged,
-                     GetWeakPtr(), !is_in_foreground_));
+                     GetWeakPtr(),
+                     !identity_manager_observer_.IsObservingSources()));
 }
 
 bool AuthenticationService::HandleMDMNotification(ChromeIdentity* identity,
@@ -517,12 +493,7 @@
 }
 
 void AuthenticationService::HandleIdentityListChanged(bool should_prompt) {
-  ReloadCredentialsFromIdentities(should_prompt);
-
-  if (is_in_foreground_) {
-    // Update the accounts currently stored in the profile prefs.
-    StoreAccountsInPrefs();
-  }
+  ComputeHaveAccountsChanged(should_prompt);
 }
 
 void AuthenticationService::HandleForgottenIdentity(
@@ -561,17 +532,11 @@
   }
 }
 
-bool AuthenticationService::IsAuthenticated() {
-  if (!is_in_foreground_) {
-    // While AuthenticationService is in background, the list of accounts can
-    // change without a OnIdentityListChanged notification being fired.
-    // Reload credentials to ensure that the user is still authenticated.
-    ReloadCredentialsFromIdentities(true /* should_prompt */);
-  }
+bool AuthenticationService::IsAuthenticated() const {
   return identity_manager_->HasPrimaryAccount();
 }
 
-bool AuthenticationService::IsAuthenticatedIdentityManaged() {
+bool AuthenticationService::IsAuthenticatedIdentityManaged() const {
   base::Optional<AccountInfo> primary_account_info =
       identity_manager_->FindExtendedAccountInfoForAccount(
           identity_manager_->GetPrimaryAccountInfo());
diff --git a/ios/chrome/browser/signin/authentication_service_fake.h b/ios/chrome/browser/signin/authentication_service_fake.h
index fcc6acfc..9361ac0 100644
--- a/ios/chrome/browser/signin/authentication_service_fake.h
+++ b/ios/chrome/browser/signin/authentication_service_fake.h
@@ -34,11 +34,11 @@
 
   void SetHaveAccountsChanged(bool changed);
 
-  bool HaveAccountsChanged() override;
+  bool HaveAccountsChanged() const override;
 
-  bool IsAuthenticated() override;
+  bool IsAuthenticated() const override;
 
-  ChromeIdentity* GetAuthenticatedIdentity() override;
+  ChromeIdentity* GetAuthenticatedIdentity() const override;
 
  private:
   AuthenticationServiceFake(PrefService* pref_service,
diff --git a/ios/chrome/browser/signin/authentication_service_fake.mm b/ios/chrome/browser/signin/authentication_service_fake.mm
index 6613f5e..8265a46c 100644
--- a/ios/chrome/browser/signin/authentication_service_fake.mm
+++ b/ios/chrome/browser/signin/authentication_service_fake.mm
@@ -53,15 +53,15 @@
   have_accounts_changed_ = changed;
 }
 
-bool AuthenticationServiceFake::HaveAccountsChanged() {
+bool AuthenticationServiceFake::HaveAccountsChanged() const {
   return have_accounts_changed_;
 }
 
-bool AuthenticationServiceFake::IsAuthenticated() {
+bool AuthenticationServiceFake::IsAuthenticated() const {
   return authenticated_identity_ != nil;
 }
 
-ChromeIdentity* AuthenticationServiceFake::GetAuthenticatedIdentity() {
+ChromeIdentity* AuthenticationServiceFake::GetAuthenticatedIdentity() const {
   return authenticated_identity_;
 }
 
diff --git a/ios/chrome/browser/signin/authentication_service_unittest.mm b/ios/chrome/browser/signin/authentication_service_unittest.mm
index b62d3c8..1b35bc92 100644
--- a/ios/chrome/browser/signin/authentication_service_unittest.mm
+++ b/ios/chrome/browser/signin/authentication_service_unittest.mm
@@ -191,16 +191,12 @@
     return authentication_service_->GetAccountsInPrefs();
   }
 
-  void SetAuthenticationServiceInForeground(bool is_in_foreground) {
-    authentication_service_->is_in_foreground_ = is_in_foreground;
+  void FireApplicationWillEnterForeground() {
+    authentication_service_->OnApplicationWillEnterForeground();
   }
 
-  void FireApplicationEnterForeground() {
-    authentication_service_->OnApplicationEnterForeground();
-  }
-
-  void FireApplicationEnterBackground() {
-    authentication_service_->OnApplicationEnterBackground();
+  void FireApplicationDidEnterBackground() {
+    authentication_service_->OnApplicationDidEnterBackground();
   }
 
   void FireAccessTokenRefreshFailed(ChromeIdentity* identity,
@@ -362,8 +358,8 @@
 
   // Set the authentication service as "In Foreground", remove identity and run
   // the loop.
-  SetAuthenticationServiceInForeground(false);
-  FireApplicationEnterForeground();
+  FireApplicationDidEnterBackground();
+  FireApplicationWillEnterForeground();
   identity_service_->ForgetIdentity(identity_, nil);
   base::RunLoop().RunUntilIdle();
 
@@ -381,7 +377,7 @@
 
   // Set the authentication service as "In Background", remove identity and run
   // the loop.
-  FireApplicationEnterBackground();
+  FireApplicationDidEnterBackground();
   identity_service_->ForgetIdentity(identity_, nil);
   base::RunLoop().RunUntilIdle();
 
@@ -457,8 +453,8 @@
 
   // Simulate a switching to background and back to foreground, triggering a
   // credentials reload.
-  FireApplicationEnterBackground();
-  FireApplicationEnterForeground();
+  FireApplicationDidEnterBackground();
+  FireApplicationWillEnterForeground();
 
   // Accounts are reloaded, "foo3@foo.com" is added as it is now in
   // ChromeIdentityService.
@@ -496,8 +492,8 @@
   base::RunLoop().RunUntilIdle();
 
   // Simulate a switching to background and back to foreground.
-  FireApplicationEnterBackground();
-  FireApplicationEnterForeground();
+  FireApplicationDidEnterBackground();
+  FireApplicationWillEnterForeground();
 
   EXPECT_FALSE(authentication_service_->HaveAccountsChanged());
 }
@@ -512,9 +508,9 @@
 
   // Simulate a switching to background and back to foreground, changing the
   // accounts while in background.
-  FireApplicationEnterBackground();
+  FireApplicationDidEnterBackground();
   identity_service_->AddIdentities(@[ @"foo4" ]);
-  FireApplicationEnterForeground();
+  FireApplicationWillEnterForeground();
 
   EXPECT_TRUE(authentication_service_->HaveAccountsChanged());
 }
@@ -529,8 +525,9 @@
 
   // Simulate a switching to background, changing the accounts while in
   // background.
-  FireApplicationEnterBackground();
+  FireApplicationDidEnterBackground();
   identity_service_->AddIdentities(@[ @"foo4" ]);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_TRUE(authentication_service_->HaveAccountsChanged());
 }
@@ -543,7 +540,7 @@
 
   // Remove the signed in identity while in background, and check that
   // IsAuthenticated is up-to-date.
-  FireApplicationEnterBackground();
+  FireApplicationDidEnterBackground();
   identity_service_->ForgetIdentity(identity_, nil);
   base::RunLoop().RunUntilIdle();
 
@@ -617,13 +614,13 @@
 
   // MDM error for |identity_| is being cleared, refresh token available
   // notification will be sent.
-  FireApplicationEnterBackground();
-  FireApplicationEnterForeground();
+  FireApplicationDidEnterBackground();
+  FireApplicationWillEnterForeground();
   EXPECT_EQ(3, refresh_token_available_count_);
 
   // MDM error has already been cleared, no notification will be sent.
-  FireApplicationEnterBackground();
-  FireApplicationEnterForeground();
+  FireApplicationDidEnterBackground();
+  FireApplicationWillEnterForeground();
   EXPECT_EQ(3, refresh_token_available_count_);
 }
 
diff --git a/ios/chrome/browser/signin/identity_manager_factory.cc b/ios/chrome/browser/signin/identity_manager_factory.cc
index 8d824b91..99b868f 100644
--- a/ios/chrome/browser/signin/identity_manager_factory.cc
+++ b/ios/chrome/browser/signin/identity_manager_factory.cc
@@ -14,8 +14,10 @@
 #include "components/signin/core/browser/account_consistency_method.h"
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
 #include "components/signin/core/browser/identity_manager_wrapper.h"
-#include "components/signin/core/browser/primary_account_policy_manager.h"
+#include "components/signin/core/browser/primary_account_manager.h"
+#include "components/signin/core/browser/primary_account_policy_manager_impl.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/signin_client.h"
 #include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
@@ -64,14 +66,17 @@
     ios::ChromeBrowserState* chrome_browser_state,
     AccountTrackerService* account_tracker_service,
     ProfileOAuth2TokenService* token_service) {
-  std::unique_ptr<PrimaryAccountPolicyManager> service =
-      std::make_unique<PrimaryAccountPolicyManager>(
-          SigninClientFactory::GetForBrowserState(chrome_browser_state),
-          token_service, account_tracker_service,
-          signin::AccountConsistencyMethod::kMirror);
+  SigninClient* client =
+      SigninClientFactory::GetForBrowserState(chrome_browser_state);
+  std::unique_ptr<PrimaryAccountManager> service =
+      std::make_unique<PrimaryAccountManager>(
+          client, token_service, account_tracker_service,
+          signin::AccountConsistencyMethod::kMirror,
+          std::make_unique<PrimaryAccountPolicyManagerImpl>(client));
   service->Initialize(GetApplicationContext()->GetLocalState());
   return service;
 }
+
 }  // namespace
 
 void IdentityManagerFactory::RegisterBrowserStatePrefs(
diff --git a/ios/chrome/browser/snapshots/snapshot_cache_unittest.mm b/ios/chrome/browser/snapshots/snapshot_cache_unittest.mm
index 646adb1..62dee20 100644
--- a/ios/chrome/browser/snapshots/snapshot_cache_unittest.mm
+++ b/ios/chrome/browser/snapshots/snapshot_cache_unittest.mm
@@ -18,7 +18,7 @@
 #import "ios/chrome/browser/snapshots/snapshot_cache_internal.h"
 #import "ios/chrome/browser/snapshots/snapshot_cache_observer.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
diff --git a/ios/chrome/browser/snapshots/snapshot_generator.mm b/ios/chrome/browser/snapshots/snapshot_generator.mm
index 32b9c6a8..114eded 100644
--- a/ios/chrome/browser/snapshots/snapshot_generator.mm
+++ b/ios/chrome/browser/snapshots/snapshot_generator.mm
@@ -20,11 +20,11 @@
 #import "ios/chrome/browser/snapshots/snapshot_generator_delegate.h"
 #include "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/image/image.h"
 
diff --git a/ios/chrome/browser/snapshots/snapshot_tab_helper.mm b/ios/chrome/browser/snapshots/snapshot_tab_helper.mm
index 4477fda..c2914ddc 100644
--- a/ios/chrome/browser/snapshots/snapshot_tab_helper.mm
+++ b/ios/chrome/browser/snapshots/snapshot_tab_helper.mm
@@ -11,10 +11,10 @@
 #include "ios/chrome/browser/infobars/infobar_manager_impl.h"
 #import "ios/chrome/browser/snapshots/snapshot_generator.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/web_state.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/suggestions/suggestions_service_factory.mm b/ios/chrome/browser/suggestions/suggestions_service_factory.mm
index f822f92..2640aa1 100644
--- a/ios/chrome/browser/suggestions/suggestions_service_factory.mm
+++ b/ios/chrome/browser/suggestions/suggestions_service_factory.mm
@@ -20,7 +20,7 @@
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
 #include "ios/web/public/browser_state.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "services/identity/public/cpp/identity_manager.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
diff --git a/ios/chrome/browser/sync/glue/sync_start_util.cc b/ios/chrome/browser/sync/glue/sync_start_util.cc
index ee5393a..cecc6646 100644
--- a/ios/chrome/browser/sync/glue/sync_start_util.cc
+++ b/ios/chrome/browser/sync/glue/sync_start_util.cc
@@ -13,8 +13,8 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 
 namespace ios {
 namespace {
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index ac92066..19a3778 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -64,8 +64,8 @@
 #include "ios/chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "ios/chrome/browser/web_data_service_factory.h"
 #include "ios/chrome/common/channel_info.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm b/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm
index 4d91cf1..f1bbb8c 100644
--- a/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm
+++ b/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm
@@ -11,7 +11,7 @@
 #include "components/sync_sessions/synced_window_delegates_getter.h"
 #include "components/sync_sessions/tab_node_pool.h"
 #include "ios/chrome/browser/sessions/ios_chrome_session_tab_helper.h"
-#include "ios/web/public/favicon_status.h"
+#include "ios/web/public/favicon/favicon_status.h"
 #include "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
diff --git a/ios/chrome/browser/sync/profile_sync_service_factory.cc b/ios/chrome/browser/sync/profile_sync_service_factory.cc
index 56328ab5..1f4a2fdc 100644
--- a/ios/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/ios/chrome/browser/sync/profile_sync_service_factory.cc
@@ -47,8 +47,8 @@
 #include "ios/chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "ios/chrome/browser/web_data_service_factory.h"
 #include "ios/chrome/common/channel_info.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/sync/session_sync_service_factory.mm b/ios/chrome/browser/sync/session_sync_service_factory.mm
index 3d6ce067..26bd48a 100644
--- a/ios/chrome/browser/sync/session_sync_service_factory.mm
+++ b/ios/chrome/browser/sync/session_sync_service_factory.mm
@@ -27,7 +27,7 @@
 #import "ios/chrome/browser/sync/sessions/ios_chrome_local_session_event_router.h"
 #include "ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.h"
 #include "ios/chrome/common/channel_info.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index e37d778..1081e526 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -68,20 +68,20 @@
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
 #import "ios/web/public/deprecated/crw_js_injection_receiver.h"
-#include "ios/web/public/favicon_status.h"
-#include "ios/web/public/favicon_url.h"
+#include "ios/web/public/favicon/favicon_status.h"
+#include "ios/web/public/favicon/favicon_url.h"
 #import "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
 #include "ios/web/public/referrer.h"
 #include "ios/web/public/security/ssl_status.h"
 #include "ios/web/public/security/web_interstitial.h"
 #import "ios/web/public/session/serializable_user_data_manager.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/url_scheme_util.h"
 #include "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
-#include "ios/web/public/web_thread.h"
 #import "ios/web/web_state/ui/crw_web_controller.h"
 #import "ios/web/web_state/web_state_impl.h"
 #include "net/base/escape.h"
diff --git a/ios/chrome/browser/tabs/tab_model.mm b/ios/chrome/browser/tabs/tab_model.mm
index a813b48..0229757 100644
--- a/ios/chrome/browser/tabs/tab_model.mm
+++ b/ios/chrome/browser/tabs/tab_model.mm
@@ -61,10 +61,10 @@
 #include "ios/web/public/security/certificate_policy_cache.h"
 #import "ios/web/public/session/serializable_user_data_manager.h"
 #include "ios/web/public/session/session_certificate_policy_cache.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/tabs/tab_model_unittest.mm b/ios/chrome/browser/tabs/tab_model_unittest.mm
index 564580c..995e622 100644
--- a/ios/chrome/browser/tabs/tab_model_unittest.mm
+++ b/ios/chrome/browser/tabs/tab_model_unittest.mm
@@ -39,7 +39,7 @@
 #import "ios/web/public/session/serializable_user_data_manager.h"
 #include "ios/web/public/test/scoped_testing_web_client.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/web_state/web_state_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 7e9c8d1..562e2c2 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -8,31 +8,24 @@
 #import <MessageUI/MessageUI.h>
 
 #include "base/base64.h"
-#include "base/bind.h"
-#include "base/feature_list.h"
-#include "base/files/file_path.h"
-#include "base/ios/block_types.h"
 #include "base/ios/ios_util.h"
-#include "base/logging.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/foundation_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
 #include "components/feature_engagement/public/event_constants.h"
 #include "components/feature_engagement/public/tracker.h"
 #import "components/language/ios/browser/ios_language_detection_tab_helper.h"
 #include "components/omnibox/browser/location_bar_model_impl.h"
 #include "components/reading_list/core/reading_list_model.h"
 #include "components/search_engines/template_url_service.h"
-#include "components/sessions/core/session_types.h"
 #include "components/sessions/core/tab_restore_service_helper.h"
 #include "components/signin/core/browser/account_reconcilor.h"
-#include "components/signin/core/browser/signin_metrics.h"
 #import "components/signin/ios/browser/account_consistency_service.h"
 #include "components/signin/ios/browser/active_state_manager.h"
+#import "components/signin/ios/browser/manage_accounts_delegate.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/translate/core/browser/translate_manager.h"
 #include "components/unified_consent/feature.h"
@@ -69,14 +62,12 @@
 #include "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h"
 #import "ios/chrome/browser/signin/account_consistency_service_factory.h"
 #include "ios/chrome/browser/signin/account_reconcilor_factory.h"
-#import "ios/chrome/browser/snapshots/snapshot_generator_delegate.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
 #import "ios/chrome/browser/ssl/captive_portal_detector_tab_helper.h"
 #import "ios/chrome/browser/ssl/captive_portal_detector_tab_helper_delegate.h"
 #include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/tabs/legacy_tab_helper.h"
 #import "ios/chrome/browser/tabs/tab.h"
-#import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/tabs/tab_private.h"
 #import "ios/chrome/browser/translate/chrome_ios_translate_client.h"
 #import "ios/chrome/browser/ui/activity_services/activity_service_legacy_coordinator.h"
@@ -91,15 +82,10 @@
 #import "ios/chrome/browser/ui/browser_view/key_commands_provider.h"
 #import "ios/chrome/browser/ui/bubble/bubble_presenter.h"
 #import "ios/chrome/browser/ui/bubble/bubble_presenter_delegate.h"
-#import "ios/chrome/browser/ui/commands/application_commands.h"
-#import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
-#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
-#import "ios/chrome/browser/ui/commands/popup_menu_commands.h"
 #import "ios/chrome/browser/ui/commands/reading_list_add_command.h"
 #import "ios/chrome/browser/ui/commands/send_tab_to_self_command.h"
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
-#import "ios/chrome/browser/ui/commands/toolbar_commands.h"
 #import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h"
 #import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h"
 #import "ios/chrome/browser/ui/context_menu/context_menu_item.h"
@@ -154,7 +140,6 @@
 #import "ios/chrome/browser/ui/toolbar/fullscreen/toolbar_ui.h"
 #import "ios/chrome/browser/ui/toolbar/fullscreen/toolbar_ui_broadcasting_util.h"
 #import "ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.h"
-#import "ios/chrome/browser/ui/toolbar/public/primary_toolbar_coordinator.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_utils.h"
 #import "ios/chrome/browser/ui/toolbar/secondary_toolbar_coordinator.h"
@@ -167,7 +152,6 @@
 #import "ios/chrome/browser/ui/util/named_guide_util.h"
 #import "ios/chrome/browser/ui/util/page_animation_util.h"
 #import "ios/chrome/browser/ui/util/pasteboard_util.h"
-#include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/browser/ui/voice/text_to_speech_playback_controller.h"
 #import "ios/chrome/browser/ui/voice/text_to_speech_playback_controller_factory.h"
@@ -183,12 +167,10 @@
 #import "ios/chrome/browser/voice/voice_search_navigations_tab_helper.h"
 #import "ios/chrome/browser/web/blocked_popup_tab_helper.h"
 #import "ios/chrome/browser/web/image_fetch_tab_helper.h"
-#import "ios/chrome/browser/web/load_timing_tab_helper.h"
 #import "ios/chrome/browser/web/page_placeholder_tab_helper.h"
 #import "ios/chrome/browser/web/repost_form_tab_helper.h"
 #import "ios/chrome/browser/web/sad_tab_tab_helper.h"
 #import "ios/chrome/browser/web/tab_id_tab_helper.h"
-#import "ios/chrome/browser/web/web_navigation_util.h"
 #include "ios/chrome/browser/web_state_list/all_web_state_observation_forwarder.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
@@ -204,37 +186,25 @@
 #include "ios/public/provider/chrome/browser/voice/voice_search_controller.h"
 #include "ios/public/provider/chrome/browser/voice/voice_search_provider.h"
 #import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h"
-#include "ios/web/common/features.h"
-#include "ios/web/common/referrer_util.h"
 #import "ios/web/public/deprecated/crw_js_injection_receiver.h"
 #import "ios/web/public/deprecated/crw_native_content_holder.h"
 #import "ios/web/public/deprecated/crw_native_content_provider.h"
 #include "ios/web/public/navigation_item.h"
-#import "ios/web/public/navigation_manager.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/url_scheme_util.h"
-#include "ios/web/public/user_agent.h"
 #include "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/context_menu_params.h"
-#import "ios/web/public/web_state/navigation_context.h"
 #import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
-#import "ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h"
-#import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_delegate_bridge.h"
 #include "ios/web/public/web_state/web_state_observer_bridge.h"
-#include "ios/web/public/web_thread.h"
 #import "ios/web/web_state/ui/crw_web_controller.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/page_transition_types.h"
-#include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
 using base::UserMetricsAction;
-using bookmarks::BookmarkNode;
 
 namespace {
 
diff --git a/ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.mm b/ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.mm
index d4523976..93340d44 100644
--- a/ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.mm
+++ b/ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.mm
@@ -4,7 +4,7 @@
 
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/first_run/first_run_util.mm b/ios/chrome/browser/ui/first_run/first_run_util.mm
index 995e34da..9f75f0a 100644
--- a/ios/chrome/browser/ui/first_run/first_run_util.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_util.mm
@@ -22,7 +22,7 @@
 #import "ios/chrome/browser/ui/settings/sync/utils/sync_util.h"
 #import "ios/chrome/browser/ui/settings/utils/settings_utils.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "services/identity/public/cpp/identity_manager.h"
 #import "ui/gfx/ios/NSString+CrStringDrawing.h"
 
diff --git a/ios/chrome/browser/ui/image_util/image_copier.mm b/ios/chrome/browser/ui/image_util/image_copier.mm
index c8d4fee..ff0625ae 100644
--- a/ios/chrome/browser/ui/image_util/image_copier.mm
+++ b/ios/chrome/browser/ui/image_util/image_copier.mm
@@ -15,8 +15,8 @@
 #import "ios/chrome/browser/ui/image_util/image_util.h"
 #import "ios/chrome/browser/web/image_fetch_tab_helper.h"
 #include "ios/chrome/grit/ios_strings.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.mm
index 2cff38b..b5d6be3 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.mm
@@ -24,7 +24,7 @@
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/url_request/url_request_context_getter.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/open_in/open_in_controller.mm b/ios/chrome/browser/ui/open_in/open_in_controller.mm
index a6b38f1..f0a66a9 100644
--- a/ios/chrome/browser/ui/open_in/open_in_controller.mm
+++ b/ios/chrome/browser/ui/open_in/open_in_controller.mm
@@ -21,10 +21,10 @@
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
 #import "ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h"
 #import "ios/web/public/web_state/web_state.h"
-#include "ios/web/public/web_thread.h"
 #include "net/base/load_flags.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
diff --git a/ios/chrome/browser/ui/payments/payment_request_manager.mm b/ios/chrome/browser/ui/payments/payment_request_manager.mm
index b8b02aa9..ff2fa9d6 100644
--- a/ios/chrome/browser/ui/payments/payment_request_manager.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_manager.mm
@@ -59,7 +59,7 @@
 #include "ios/web/common/origin_util.h"
 #import "ios/web/public/deprecated/crw_js_injection_receiver.h"
 #include "ios/web/public/deprecated/url_verification_constants.h"
-#include "ios/web/public/favicon_status.h"
+#include "ios/web/public/favicon/favicon_status.h"
 #include "ios/web/public/js_messaging/web_frame.h"
 #include "ios/web/public/js_messaging/web_frame_util.h"
 #import "ios/web/public/js_messaging/web_frames_manager.h"
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
index aaebd7c8..185eaf1 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
@@ -41,7 +41,7 @@
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h"
-#include "ios/web/public/favicon_status.h"
+#include "ios/web/public/favicon/favicon_status.h"
 #import "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
 #include "ios/web/public/navigation_manager.h"
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm
index b2f2792..0a7f4885 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm
@@ -15,6 +15,7 @@
 #include "components/google/core/common/google_util.h"
 #include "components/history/core/browser/web_history_service.h"
 #include "components/prefs/ios/pref_observer_bridge.h"
+#include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/sync/driver/sync_service.h"
diff --git a/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm b/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
index d18f74f..55e1dc10 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/callback.h"
+#include "base/ios/ios_util.h"
 #include "base/mac/foundation_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/stringprintf.h"
@@ -251,18 +252,30 @@
 // Matches the pop-up (call-out) menu item with accessibility label equal to the
 // translated string identified by |label|.
 id<GREYMatcher> PopUpMenuItemWithLabel(int label) {
-  // This is a hack relying on UIKit's internal structure. There are multiple
-  // items with the label the test is looking for, because the menu items likely
-  // have the same labels as the buttons for the same function. There is no easy
-  // way to identify elements which are part of the pop-up, because the
-  // associated classes are internal to UIKit. However, the pop-up items are
-  // composed of a button-type element (without accessibility traits of a
-  // button) owning a label, both with the same accessibility labels. This is
-  // differentiating the pop-up items from the other buttons.
-  return grey_allOf(
-      grey_accessibilityLabel(l10n_util::GetNSString(label)),
-      MatchParentWith(grey_accessibilityLabel(l10n_util::GetNSString(label))),
-      nullptr);
+  if (@available(iOS 13, *)) {
+    // iOS13 reworked menu button subviews to no longer be accessibility
+    // elements.  Multiple menu button subviews no longer show up as potential
+    // matches, which means the matcher logic does not need to be as complex as
+    // the iOS 11/12 logic.  Various table view cells may share the same
+    // accesibility label, but those can be filtered out by ignoring
+    // UIAccessibilityTraitButton.
+    return grey_allOf(
+        grey_accessibilityLabel(l10n_util::GetNSString(label)),
+        grey_not(grey_accessibilityTrait(UIAccessibilityTraitButton)), nil);
+  } else {
+    // This is a hack relying on UIKit's internal structure. There are multiple
+    // items with the label the test is looking for, because the menu items
+    // likely have the same labels as the buttons for the same function. There
+    // is no easy way to identify elements which are part of the pop-up, because
+    // the associated classes are internal to UIKit. However, the pop-up items
+    // are composed of a button-type element (without accessibility traits of a
+    // button) owning a label, both with the same accessibility labels. This is
+    // differentiating the pop-up items from the other buttons.
+    return grey_allOf(
+        grey_accessibilityLabel(l10n_util::GetNSString(label)),
+        MatchParentWith(grey_accessibilityLabel(l10n_util::GetNSString(label))),
+        nullptr);
+  }
 }
 
 scoped_refptr<password_manager::PasswordStore> GetPasswordStore() {
@@ -1524,10 +1537,13 @@
                    chrome_test_util::ButtonWithAccessibilityLabelId(
                        IDS_IOS_EXPORT_PASSWORDS)] performAction:grey_tap()];
   } else {
-    // Tap on the "Cancel" button accompanying the activity view to dismiss it.
+    // Tap on the "Cancel" or "X" button accompanying the activity view to
+    // dismiss it.
+    NSString* dismissLabel =
+        base::ios::IsRunningOnIOS13OrLater() ? @"xmark" : @"Cancel";
     [[EarlGrey
         selectElementWithMatcher:grey_allOf(
-                                     ButtonWithAccessibilityLabel(@"Cancel"),
+                                     ButtonWithAccessibilityLabel(dismissLabel),
                                      grey_interactable(), nullptr)]
         performAction:grey_tap()];
   }
diff --git a/ios/chrome/browser/ui/settings/settings_egtest.mm b/ios/chrome/browser/ui/settings/settings_egtest.mm
index 20111b1..d74428d4 100644
--- a/ios/chrome/browser/ui/settings/settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/settings_egtest.mm
@@ -35,9 +35,9 @@
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
 #import "ios/web/public/test/http_server/http_server.h"
 #include "ios/web/public/test/http_server/http_server_util.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state/web_state.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -173,8 +173,20 @@
 
   // Before returning, make sure that the top of the Clear Browsing Data
   // settings screen is visible to match the state at the start of the method.
+  // TODO(crbug.com/973708): On iOS 13 the settings menu appears as a card that
+  // can be dismissed with a downward swipe.  This make it difficult to use a
+  // gesture to return to the top of the Clear Browsing Data screen, so scroll
+  // programatically instead. Remove this custom action if we switch back to a
+  // fullscreen presentation.
+  GREYPerformBlock scrollToTopBlock =
+      ^BOOL(id element, __strong NSError** error) {
+        UIScrollView* view = base::mac::ObjCCastStrict<UIScrollView>(element);
+        view.contentOffset = CGPointZero;
+        return YES;
+      };
   [[EarlGrey selectElementWithMatcher:ClearBrowsingDataView()]
-      performAction:grey_scrollToContentEdge(kGREYContentEdgeTop)];
+      performAction:[GREYActionBlock actionWithName:@"Scroll to top"
+                                       performBlock:scrollToTopBlock]];
 }
 
 // From the NTP, clears the cookies and site data via the UI.
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
index 25613fbd..e0e34098 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -31,8 +31,8 @@
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/util/uikit_ui_util.mm b/ios/chrome/browser/ui/util/uikit_ui_util.mm
index bb1ee5a..2184bf7 100644
--- a/ios/chrome/browser/ui/util/uikit_ui_util.mm
+++ b/ios/chrome/browser/ui/util/uikit_ui_util.mm
@@ -21,7 +21,7 @@
 #include "ios/chrome/browser/ui/util/dynamic_type_util.h"
 #include "ios/chrome/browser/ui/util/rtl_geometry.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ios/chrome/browser/ui/webui/net_export/net_export_ui.mm b/ios/chrome/browser/ui/webui/net_export/net_export_ui.mm
index 9534592..3ba0844 100644
--- a/ios/chrome/browser/ui/webui/net_export/net_export_ui.mm
+++ b/ios/chrome/browser/ui/webui/net_export/net_export_ui.mm
@@ -23,8 +23,8 @@
 #import "ios/chrome/browser/webui/show_mail_composer_context.h"
 #include "ios/chrome/common/channel_info.h"
 #include "ios/chrome/grit/ios_strings.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state/web_state.h"
-#include "ios/web/public/web_thread.h"
 #include "ios/web/public/webui/web_ui_ios.h"
 #include "ios/web/public/webui/web_ui_ios_data_source.h"
 #include "ios/web/public/webui/web_ui_ios_message_handler.h"
diff --git a/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc b/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
index 18dfb340..bc5f666e 100644
--- a/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
+++ b/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
@@ -16,7 +16,7 @@
 #include "ios/chrome/browser/favicon/favicon_service_factory.h"
 #include "ios/chrome/browser/ntp_tiles/ios_most_visited_sites_factory.h"
 #include "ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/webui/web_ui_ios.h"
 #include "ios/web/public/webui/web_ui_ios_data_source.h"
 #include "ios/web/public/webui/web_ui_ios_message_handler.h"
diff --git a/ios/chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.cc b/ios/chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.cc
index 95dc557..ba960f3 100644
--- a/ios/chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.cc
+++ b/ios/chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.cc
@@ -24,7 +24,7 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
 #include "ios/chrome/common/channel_info.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/webui/web_ui_ios.h"
 
 namespace {
diff --git a/ios/chrome/browser/web/dom_altering_lock.mm b/ios/chrome/browser/web/dom_altering_lock.mm
index 0fd524a4..a742820 100644
--- a/ios/chrome/browser/web/dom_altering_lock.mm
+++ b/ios/chrome/browser/web/dom_altering_lock.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/web/dom_altering_lock.h"
 
 #include "base/logging.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/web/image_fetch_tab_helper.mm b/ios/chrome/browser/web/image_fetch_tab_helper.mm
index 685fc9e..201975b 100644
--- a/ios/chrome/browser/web/image_fetch_tab_helper.mm
+++ b/ios/chrome/browser/web/image_fetch_tab_helper.mm
@@ -14,9 +14,9 @@
 #include "components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h"
 #include "ios/web/common/referrer_util.h"
 #include "ios/web/public/browser_state.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state/navigation_context.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/web_data_service_factory.cc b/ios/chrome/browser/web_data_service_factory.cc
index 0975b175..99a1fb3 100644
--- a/ios/chrome/browser/web_data_service_factory.cc
+++ b/ios/chrome/browser/web_data_service_factory.cc
@@ -19,8 +19,8 @@
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 
 namespace ios {
 
diff --git a/ios/components/io_thread/ios_io_thread.h b/ios/components/io_thread/ios_io_thread.h
index 21eaee76..b04cd4e2 100644
--- a/ios/components/io_thread/ios_io_thread.h
+++ b/ios/components/io_thread/ios_io_thread.h
@@ -19,7 +19,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "components/prefs/pref_member.h"
-#include "ios/web/public/web_thread_delegate.h"
+#include "ios/web/public/thread/web_thread_delegate.h"
 #include "net/base/network_change_notifier.h"
 #include "net/http/http_network_session.h"
 
diff --git a/ios/components/io_thread/ios_io_thread.mm b/ios/components/io_thread/ios_io_thread.mm
index 5fa5d9b..c9b1887 100644
--- a/ios/components/io_thread/ios_io_thread.mm
+++ b/ios/components/io_thread/ios_io_thread.mm
@@ -33,10 +33,10 @@
 #include "components/proxy_config/pref_proxy_config_tracker.h"
 #include "components/variations/variations_associated_data.h"
 #include "components/version_info/version_info.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/user_agent.h"
 #include "ios/web/public/web_client.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
 #include "net/base/logging_network_change_observer.h"
 #include "net/cert/cert_verifier.h"
 #include "net/cert/ct_policy_enforcer.h"
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index f6afc02b..c1717dc 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -45,6 +45,7 @@
     "//base",
     "//ios/web/common",
     "//ios/web/download",
+    "//ios/web/favicon",
     "//ios/web/init",
     "//ios/web/navigation",
     "//ios/web/net",
@@ -53,6 +54,7 @@
     "//ios/web/public/session",
     "//ios/web/security",
     "//ios/web/session",
+    "//ios/web/thread",
     "//ios/web/web_state",
     "//ios/web/web_state:web_view_internal_creation_util",
     "//services/network:network_service",
@@ -618,6 +620,7 @@
     "//ios/web:resources_grit",
     "//ios/web/common",
     "//ios/web/download:download_inttests",
+    "//ios/web/favicon:inttests",
     "//ios/web/js_messaging:inttests",
     "//ios/web/navigation",
     "//ios/web/navigation:core",
@@ -658,7 +661,6 @@
     "url_loader_inttest.mm",
     "web_state/bad_ssl_response_inttest.mm",
     "web_state/error_page_inttest.mm",
-    "web_state/favicon_callbacks_inttest.mm",
     "web_state/http_auth_inttest.mm",
     "web_state/keep_render_process_alive_inttest.mm",
     "web_state/web_state_observer_inttest.mm",
diff --git a/ios/web/browser_state.mm b/ios/web/browser_state.mm
index 4479371..d0adaf86 100644
--- a/ios/web/browser_state.mm
+++ b/ios/web/browser_state.mm
@@ -19,9 +19,9 @@
 #include "ios/web/public/security/certificate_policy_cache.h"
 #include "ios/web/public/service_manager_connection.h"
 #include "ios/web/public/service_names.mojom.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/web_client.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
 #include "ios/web/webui/url_data_manager_ios_backend.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "mojo/public/cpp/bindings/remote.h"
diff --git a/ios/web/browsing_data/browsing_data_remover.mm b/ios/web/browsing_data/browsing_data_remover.mm
index d850bdea..06f9258 100644
--- a/ios/web/browsing_data/browsing_data_remover.mm
+++ b/ios/web/browsing_data/browsing_data_remover.mm
@@ -10,7 +10,7 @@
 #include "base/task/post_task.h"
 #import "ios/web/browsing_data/browsing_data_remover_observer.h"
 #import "ios/web/public/browser_state.h"
-#import "ios/web/public/web_thread.h"
+#import "ios/web/public/thread/web_thread.h"
 #import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/web/download/download_task_impl.mm b/ios/web/download/download_task_impl.mm
index 8c074ae3..9932993 100644
--- a/ios/web/download/download_task_impl.mm
+++ b/ios/web/download/download_task_impl.mm
@@ -13,9 +13,9 @@
 #import "ios/web/net/cookies/wk_cookie_util.h"
 #include "ios/web/public/browser_state.h"
 #import "ios/web/public/download/download_task_observer.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_state/web_state.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
 #import "ios/web/web_view/error_translation_util.h"
 #include "net/base/completion_once_callback.h"
 #include "net/base/data_url.h"
diff --git a/ios/web/favicon/BUILD.gn b/ios/web/favicon/BUILD.gn
new file mode 100644
index 0000000..f4269b0d
--- /dev/null
+++ b/ios/web/favicon/BUILD.gn
@@ -0,0 +1,31 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//ios/build/config.gni")
+
+source_set("favicon") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  deps = [
+    "//ios/web/public",
+  ]
+  sources = [
+    "favicon_status.cc",
+    "favicon_url.cc",
+  ]
+}
+
+source_set("inttests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//ios/web/public",
+    "//ios/web/public:web_state_types",
+    "//ios/web/public/test",
+  ]
+  sources = [
+    "favicon_callbacks_inttest.mm",
+  ]
+}
diff --git a/ios/web/web_state/favicon_callbacks_inttest.mm b/ios/web/favicon/favicon_callbacks_inttest.mm
similarity index 99%
rename from ios/web/web_state/favicon_callbacks_inttest.mm
rename to ios/web/favicon/favicon_callbacks_inttest.mm
index 64f1715..2c99068 100644
--- a/ios/web/web_state/favicon_callbacks_inttest.mm
+++ b/ios/web/favicon/favicon_callbacks_inttest.mm
@@ -5,7 +5,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #import "base/test/ios/wait_util.h"
-#include "ios/web/public/favicon_url.h"
+#include "ios/web/public/favicon/favicon_url.h"
 #import "ios/web/public/test/web_test_with_web_state.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer.h"
diff --git a/ios/web/public/favicon_status.cc b/ios/web/favicon/favicon_status.cc
similarity index 63%
rename from ios/web/public/favicon_status.cc
rename to ios/web/favicon/favicon_status.cc
index 8c22443..f1a720333 100644
--- a/ios/web/public/favicon_status.cc
+++ b/ios/web/favicon/favicon_status.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ios/web/public/favicon_status.h"
+#include "ios/web/public/favicon/favicon_status.h"
 
 namespace web {
 
 FaviconStatus::FaviconStatus() : valid(false) {
-  // TODO(rohitrao): Add a GetDefaultFavicon() method to WebClient and call it
-  // here.
+  // TODO(crbug.com/973407): Add a GetDefaultFavicon() method to WebClient and
+  // call it here.
 }
 
 }  // namespace web
diff --git a/ios/web/public/favicon_url.cc b/ios/web/favicon/favicon_url.cc
similarity index 83%
rename from ios/web/public/favicon_url.cc
rename to ios/web/favicon/favicon_url.cc
index db6a68c..e045470 100644
--- a/ios/web/public/favicon_url.cc
+++ b/ios/web/favicon/favicon_url.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 "ios/web/public/favicon_url.h"
+#include "ios/web/public/favicon/favicon_url.h"
 
 namespace web {
 
@@ -15,7 +15,6 @@
 
 FaviconURL::FaviconURL(const FaviconURL& other) = default;
 
-FaviconURL::~FaviconURL() {
-}
+FaviconURL::~FaviconURL() {}
 
-} // namespace web
+}  // namespace web
diff --git a/ios/web/find_in_page/find_in_page_manager_impl.mm b/ios/web/find_in_page/find_in_page_manager_impl.mm
index 5a89a7bb..d9a4d6b 100644
--- a/ios/web/find_in_page/find_in_page_manager_impl.mm
+++ b/ios/web/find_in_page/find_in_page_manager_impl.mm
@@ -12,7 +12,7 @@
 #import "ios/web/public/js_messaging/web_frame.h"
 #include "ios/web/public/js_messaging/web_frame_util.h"
 #import "ios/web/public/js_messaging/web_frames_manager.h"
-#include "ios/web/public/web_task_traits.h"
+#include "ios/web/public/thread/web_task_traits.h"
 #import "ios/web/web_state/web_state_impl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/web/init/web_main_loop.mm b/ios/web/init/web_main_loop.mm
index f158cf4..c963e8cd 100644
--- a/ios/web/init/web_main_loop.mm
+++ b/ios/web/init/web_main_loop.mm
@@ -23,8 +23,8 @@
 #import "ios/web/net/cookie_notification_bridge.h"
 #include "ios/web/public/init/ios_global_state.h"
 #include "ios/web/public/init/web_main_parts.h"
+#include "ios/web/public/thread/web_task_traits.h"
 #import "ios/web/public/web_client.h"
-#include "ios/web/public/web_task_traits.h"
 #include "ios/web/service_manager_context.h"
 #include "ios/web/web_sub_thread.h"
 #include "ios/web/web_thread_impl.h"
diff --git a/ios/web/js_messaging/web_frame_impl.mm b/ios/web/js_messaging/web_frame_impl.mm
index 643cb89..2e73b37 100644
--- a/ios/web/js_messaging/web_frame_impl.mm
+++ b/ios/web/js_messaging/web_frame_impl.mm
@@ -16,8 +16,8 @@
 #include "base/values.h"
 #include "crypto/aead.h"
 #include "crypto/random.h"
+#include "ios/web/public/thread/web_task_traits.h"
 #import "ios/web/public/web_state/web_state.h"
-#include "ios/web/public/web_task_traits.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm
index ac03ac5..e8ee963a4 100644
--- a/ios/web/navigation/crw_wk_navigation_handler.mm
+++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -539,6 +539,8 @@
     // May happen on iOS9, however in didCommitNavigation: callback the URL
     // will be "about:blank".
     webViewURL = GURL(url::kAboutBlankURL);
+    UMA_HISTOGRAM_BOOLEAN("IOS.WKWebViewStartProvisionalNavigationWithEmptyURL",
+                          true);
   }
 
   web::NavigationContextImpl* context =
@@ -2000,6 +2002,11 @@
   // they should have already been triggered during navigation commit for
   // failures that happen after commit.
   [self.delegate navigationHandlerDidStartLoading:self];
+  // TODO(crbug.com/973765): This is a workaround because |item| might get
+  // released after
+  // |self.navigationManagerImpl->CommitPendingItem(context->ReleaseItem()|.
+  // Remove this once navigation refactor is done.
+  GURL itemURL = item->GetURL();
   self.navigationManagerImpl->CommitPendingItem(context->ReleaseItem());
   web::NavigationItem* lastCommittedItem =
       self.navigationManagerImpl->GetLastCommittedItem();
@@ -2013,7 +2020,7 @@
   // is also needed if |context| is not yet committed, which can happen on a
   // reload/back/forward load that failed in provisional navigation.
   if (context->IsPlaceholderNavigation() || !context->HasCommitted()) {
-    context->SetUrl(item->GetURL());
+    context->SetUrl(itemURL);
     context->SetPlaceholderNavigation(false);
     context->SetHasCommitted(true);
     self.webStateImpl->OnNavigationFinished(context);
diff --git a/ios/web/navigation/navigation_item_impl.h b/ios/web/navigation/navigation_item_impl.h
index 5a9b632..b0d10d25 100644
--- a/ios/web/navigation/navigation_item_impl.h
+++ b/ios/web/navigation/navigation_item_impl.h
@@ -11,7 +11,7 @@
 
 #include "base/strings/string16.h"
 #include "ios/web/navigation/error_retry_state_machine.h"
-#include "ios/web/public/favicon_status.h"
+#include "ios/web/public/favicon/favicon_status.h"
 #import "ios/web/public/navigation_item.h"
 #include "ios/web/public/referrer.h"
 #include "ios/web/public/security/ssl_status.h"
diff --git a/ios/web/net/cookie_notification_bridge.mm b/ios/web/net/cookie_notification_bridge.mm
index 27715762..b7ec466 100644
--- a/ios/web/net/cookie_notification_bridge.mm
+++ b/ios/web/net/cookie_notification_bridge.mm
@@ -10,8 +10,8 @@
 #include "base/location.h"
 #include "base/task/post_task.h"
 #import "ios/net/cookies/cookie_store_ios.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/web/net/cookies/crw_wk_http_cookie_store.mm b/ios/web/net/cookies/crw_wk_http_cookie_store.mm
index 0be7b9b..8c068afb 100644
--- a/ios/web/net/cookies/crw_wk_http_cookie_store.mm
+++ b/ios/web/net/cookies/crw_wk_http_cookie_store.mm
@@ -5,7 +5,7 @@
 #import "ios/web/net/cookies/crw_wk_http_cookie_store.h"
 
 #include "base/logging.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/web/net/cookies/wk_http_system_cookie_store.mm b/ios/web/net/cookies/wk_http_system_cookie_store.mm
index dd9cbc2..5b5eba4 100644
--- a/ios/web/net/cookies/wk_http_system_cookie_store.mm
+++ b/ios/web/net/cookies/wk_http_system_cookie_store.mm
@@ -9,8 +9,8 @@
 #include "base/task/post_task.h"
 #import "ios/net/cookies/cookie_creation_time_manager.h"
 #include "ios/net/cookies/system_cookie_util.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
 #import "net/base/mac/url_conversions.h"
 #include "net/cookies/canonical_cookie.h"
diff --git a/ios/web/network_context_owner.cc b/ios/web/network_context_owner.cc
index a89c9e0f..0fdb956 100644
--- a/ios/web/network_context_owner.cc
+++ b/ios/web/network_context_owner.cc
@@ -10,8 +10,8 @@
 
 #include "base/bind.h"
 #include "base/task/post_task.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_context_getter_observer.h"
 #include "services/network/network_context.h"
diff --git a/ios/web/network_context_owner_unittest.cc b/ios/web/network_context_owner_unittest.cc
index 40e6804..00526a88 100644
--- a/ios/web/network_context_owner_unittest.cc
+++ b/ios/web/network_context_owner_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/run_loop.h"
 #include "base/task/post_task.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
-#include "ios/web/public/web_task_traits.h"
+#include "ios/web/public/thread/web_task_traits.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_test_util.h"
diff --git a/ios/web/public/BUILD.gn b/ios/web/public/BUILD.gn
index e6586a6..66eb0be 100644
--- a/ios/web/public/BUILD.gn
+++ b/ios/web/public/BUILD.gn
@@ -9,6 +9,8 @@
     ":referrer",
     ":user_agent",
     ":web_state_types",
+    "//ios/web/public/favicon",
+    "//ios/web/public/thread",
     "//net",
     "//services/network/public/cpp",
     "//services/network/public/mojom",
@@ -24,10 +26,6 @@
   sources = [
     "browser_state.h",
     "browser_url_rewriter.h",
-    "favicon_status.cc",
-    "favicon_status.h",
-    "favicon_url.cc",
-    "favicon_url.h",
     "java_script_dialog_callback.h",
     "java_script_dialog_presenter.h",
     "java_script_dialog_type.h",
@@ -53,7 +51,6 @@
     "web_state/web_state_policy_decider.h",
     "web_state/web_state_policy_decider_bridge.h",
     "web_state/web_state_user_data.h",
-    "web_task_traits.cc",
     "web_task_traits.h",
     "web_thread.h",
     "web_thread_delegate.h",
diff --git a/ios/web/public/favicon/BUILD.gn b/ios/web/public/favicon/BUILD.gn
new file mode 100644
index 0000000..517e9fa5
--- /dev/null
+++ b/ios/web/public/favicon/BUILD.gn
@@ -0,0 +1,16 @@
+# 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.
+
+source_set("favicon") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  deps = [
+    "//ui/gfx",
+    "//ui/gfx/geometry",
+    "//url",
+  ]
+  sources = [
+    "favicon_status.h",
+    "favicon_url.h",
+  ]
+}
diff --git a/ios/web/public/favicon/README.md b/ios/web/public/favicon/README.md
new file mode 100644
index 0000000..6c8f7a1f
--- /dev/null
+++ b/ios/web/public/favicon/README.md
@@ -0,0 +1 @@
+This directory contains structs which encapsulate information about web site favicons.
diff --git a/ios/web/public/favicon_status.h b/ios/web/public/favicon/favicon_status.h
similarity index 86%
rename from ios/web/public/favicon_status.h
rename to ios/web/public/favicon/favicon_status.h
index e919f83..57128cdbf 100644
--- a/ios/web/public/favicon_status.h
+++ b/ios/web/public/favicon/favicon_status.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 IOS_WEB_PUBLIC_FAVICON_STATUS_H_
-#define IOS_WEB_PUBLIC_FAVICON_STATUS_H_
+#ifndef IOS_WEB_PUBLIC_FAVICON_FAVICON_STATUS_H_
+#define IOS_WEB_PUBLIC_FAVICON_FAVICON_STATUS_H_
 
 #include "ui/gfx/image/image.h"
 #include "url/gurl.h"
@@ -32,4 +32,4 @@
 
 }  // namespace web
 
-#endif  // IOS_WEB_PUBLIC_FAVICON_STATUS_H_
+#endif  // IOS_WEB_PUBLIC_FAVICON_FAVICON_STATUS_H_
diff --git a/ios/web/public/favicon_url.h b/ios/web/public/favicon/favicon_url.h
similarity index 84%
rename from ios/web/public/favicon_url.h
rename to ios/web/public/favicon/favicon_url.h
index 2f4df255..9262f3980 100644
--- a/ios/web/public/favicon_url.h
+++ b/ios/web/public/favicon/favicon_url.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 IOS_WEB_PUBLIC_FAVICON_URL_H_
-#define IOS_WEB_PUBLIC_FAVICON_URL_H_
+#ifndef IOS_WEB_PUBLIC_FAVICON_FAVICON_URL_H_
+#define IOS_WEB_PUBLIC_FAVICON_FAVICON_URL_H_
 
 #include <vector>
 
@@ -41,6 +41,6 @@
   std::vector<gfx::Size> icon_sizes;
 };
 
-} // namespace web
+}  // namespace web
 
-#endif  // IOS_WEB_PUBLIC_FAVICON_URL_H_
+#endif  // IOS_WEB_PUBLIC_FAVICON_FAVICON_URL_H_
diff --git a/ios/web/public/init/network_context_owner.h b/ios/web/public/init/network_context_owner.h
index 5e74fa9..0727297 100644
--- a/ios/web/public/init/network_context_owner.h
+++ b/ios/web/public/init/network_context_owner.h
@@ -10,7 +10,7 @@
 #include <vector>
 
 #include "base/gtest_prod_util.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_context_getter_observer.h"
 #include "services/network/network_context.h"
diff --git a/ios/web/public/test/fakes/fake_web_frame.cc b/ios/web/public/test/fakes/fake_web_frame.cc
index f2f7d0f..ee08b23 100644
--- a/ios/web/public/test/fakes/fake_web_frame.cc
+++ b/ios/web/public/test/fakes/fake_web_frame.cc
@@ -12,7 +12,7 @@
 #include "base/json/json_writer.h"
 #include "base/task/post_task.h"
 #include "base/values.h"
-#include "ios/web/public/web_task_traits.h"
+#include "ios/web/public/thread/web_task_traits.h"
 
 namespace web {
 
diff --git a/ios/web/public/test/fakes/test_browser_state.cc b/ios/web/public/test/fakes/test_browser_state.cc
index 4feedd6..59f272e7 100644
--- a/ios/web/public/test/fakes/test_browser_state.cc
+++ b/ios/web/public/test/fakes/test_browser_state.cc
@@ -7,8 +7,8 @@
 #include "base/files/file_path.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task/post_task.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web/test/test_url_constants.h"
 #include "ios/web/webui/url_data_manager_ios_backend.h"
 #include "net/url_request/url_request_context.h"
diff --git a/ios/web/public/test/fakes/test_web_client.mm b/ios/web/public/test/fakes/test_web_client.mm
index b3ab899..1907f0c3 100644
--- a/ios/web/public/test/fakes/test_web_client.mm
+++ b/ios/web/public/test/fakes/test_web_client.mm
@@ -8,7 +8,7 @@
 
 #include "base/logging.h"
 #include "base/task/post_task.h"
-#include "ios/web/public/web_task_traits.h"
+#include "ios/web/public/thread/web_task_traits.h"
 #include "ios/web/test/test_url_constants.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "url/gurl.h"
diff --git a/ios/web/public/test/fakes/test_web_state_observer_util.h b/ios/web/public/test/fakes/test_web_state_observer_util.h
index 423d45d..d8e26a3b 100644
--- a/ios/web/public/test/fakes/test_web_state_observer_util.h
+++ b/ios/web/public/test/fakes/test_web_state_observer_util.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 
-#include "ios/web/public/favicon_url.h"
+#include "ios/web/public/favicon/favicon_url.h"
 #include "url/gurl.h"
 
 namespace web {
diff --git a/ios/web/public/test/test_web_thread.h b/ios/web/public/test/test_web_thread.h
index 449359e..a6beff3 100644
--- a/ios/web/public/test/test_web_thread.h
+++ b/ios/web/public/test/test_web_thread.h
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 
 namespace base {
 class MessageLoop;
diff --git a/ios/web/public/thread/BUILD.gn b/ios/web/public/thread/BUILD.gn
new file mode 100644
index 0000000..2e4525a
--- /dev/null
+++ b/ios/web/public/thread/BUILD.gn
@@ -0,0 +1,15 @@
+# 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.
+
+source_set("thread") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  deps = [
+    "//base",
+  ]
+  sources = [
+    "web_task_traits.h",
+    "web_thread.h",
+    "web_thread_delegate.h",
+  ]
+}
diff --git a/ios/web/public/thread/web_task_traits.h b/ios/web/public/thread/web_task_traits.h
new file mode 100644
index 0000000..bd6d569c
--- /dev/null
+++ b/ios/web/public/thread/web_task_traits.h
@@ -0,0 +1,101 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_PUBLIC_THREAD_WEB_TASK_TRAITS_H_
+#define IOS_WEB_PUBLIC_THREAD_WEB_TASK_TRAITS_H_
+
+#include "base/task/task_traits.h"
+#include "base/task/task_traits_extension.h"
+#include "ios/web/public/thread/web_thread.h"
+
+namespace web {
+
+// Tasks with this trait will not be executed inside a nested RunLoop.
+//
+// Note: This should rarely be required. Drivers of nested loops should instead
+// make sure to be reentrant when allowing nested application tasks (also rare).
+//
+// TODO(crbug.com/876272): Investigate removing this trait -- and any logic for
+// deferred tasks in MessageLoop.
+struct NonNestable {};
+
+// TaskTraits for running tasks on a WebThread.
+//
+// These traits enable the use of the //base/task/post_task.h APIs to post tasks
+// to a WebThread.
+//
+// To post a task to the UI thread (analogous for IO thread):
+//     base::PostTaskWithTraits(FROM_HERE, {WebThread::UI}, task);
+//
+// To obtain a TaskRunner for the UI thread (analogous for the IO thread):
+//     base::CreateSingleThreadTaskRunnerWithTraits({WebThread::UI});
+//
+// Tasks posted to the same WebThread with the same traits will be executed
+// in the order they were posted, regardless of the TaskRunners they were
+// posted via.
+//
+// See //base/task/post_task.h for more detailed documentation.
+//
+// Posting to a WebThread must only be done after it was initialized (ref.
+// WebMainLoop::CreateThreads() phase).
+class WebTaskTraitsExtension {
+ public:
+  static constexpr uint8_t kExtensionId =
+      base::TaskTraitsExtensionStorage::kFirstEmbedderExtensionId;
+
+  struct ValidTrait : public base::TaskTraits::ValidTrait {
+    using base::TaskTraits::ValidTrait::ValidTrait;
+
+    ValidTrait(WebThread::ID);
+    ValidTrait(NonNestable);
+  };
+
+  template <
+      class... ArgTypes,
+      class CheckArgumentsAreValid = std::enable_if_t<
+          base::trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value>>
+  constexpr WebTaskTraitsExtension(ArgTypes... args)
+      : web_thread_(base::trait_helpers::GetEnum<WebThread::ID>(args...)),
+        nestable_(!base::trait_helpers::HasTrait<NonNestable>(args...)) {}
+
+  constexpr base::TaskTraitsExtensionStorage Serialize() const {
+    static_assert(8 == sizeof(WebTaskTraitsExtension),
+                  "Update Serialize() and Parse() when changing "
+                  "WebTaskTraitsExtension");
+    return {
+        kExtensionId,
+        {static_cast<uint8_t>(web_thread_), static_cast<uint8_t>(nestable_)}};
+  }
+
+  static const WebTaskTraitsExtension Parse(
+      const base::TaskTraitsExtensionStorage& extension) {
+    return WebTaskTraitsExtension(static_cast<WebThread::ID>(extension.data[0]),
+                                  static_cast<bool>(extension.data[1]));
+  }
+
+  constexpr WebThread::ID web_thread() const { return web_thread_; }
+
+  // Returns true if tasks with these traits may run in a nested RunLoop.
+  constexpr bool nestable() const { return nestable_; }
+
+ private:
+  WebTaskTraitsExtension(WebThread::ID web_thread, bool nestable)
+      : web_thread_(web_thread), nestable_(nestable) {}
+
+  WebThread::ID web_thread_;
+  bool nestable_;
+};
+
+template <class... ArgTypes,
+          class = std::enable_if_t<base::trait_helpers::AreValidTraits<
+              WebTaskTraitsExtension::ValidTrait,
+              ArgTypes...>::value>>
+constexpr base::TaskTraitsExtensionStorage MakeTaskTraitsExtension(
+    ArgTypes&&... args) {
+  return WebTaskTraitsExtension(std::forward<ArgTypes>(args)...).Serialize();
+}
+
+}  // namespace web
+
+#endif  // IOS_WEB_PUBLIC_THREAD_WEB_TASK_TRAITS_H_
diff --git a/ios/web/public/thread/web_thread.h b/ios/web/public/thread/web_thread.h
new file mode 100644
index 0000000..46aacc8
--- /dev/null
+++ b/ios/web/public/thread/web_thread.h
@@ -0,0 +1,164 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_PUBLIC_THREAD_WEB_THREAD_H_
+#define IOS_WEB_PUBLIC_THREAD_WEB_THREAD_H_
+
+#include <string>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/task_runner_util.h"
+
+namespace base {
+class Location;
+}
+
+namespace web {
+
+class WebThreadDelegate;
+
+// Use DCHECK_CURRENTLY_ON(WebThread::ID) to assert that a function can only be
+// called on the named WebThread.
+#define DCHECK_CURRENTLY_ON(thread_identifier)              \
+  (DCHECK(::web::WebThread::CurrentlyOn(thread_identifier)) \
+   << ::web::WebThread::GetDCheckCurrentlyOnErrorMessage(thread_identifier))
+
+///////////////////////////////////////////////////////////////////////////////
+// WebThread
+//
+// Utility functions for threads that are known by name. For example, there is
+// one IO thread for the entire process, and various pieces of code find it
+// useful to retrieve a pointer to the IO thread's message loop.
+//
+// See web_task_traits.h for posting Tasks to a WebThread.
+//
+// This class automatically handles the lifetime of different threads. You
+// should never need to cache pointers to MessageLoops, since they're not thread
+// safe.
+class WebThread {
+ public:
+  // An enumeration of the well-known threads.
+  // NOTE: threads must be listed in the order of their life-time, with each
+  // thread outliving every other thread below it.
+  enum ID {
+    // The main thread in the browser.
+    UI,
+
+    // This is the thread that processes non-blocking IO, i.e. IPC and network.
+    // Blocking IO should happen in ThreadPool.
+    IO,
+
+    // NOTE: do not add new threads here. Instead you should just use
+    // base::Create*TaskRunnerWithTraits to run tasks on the ThreadPool.
+
+    // This identifier does not represent a thread.  Instead it counts the
+    // number of well-known threads.  Insert new well-known threads before this
+    // identifier.
+    ID_COUNT
+  };
+
+  // NOTE: Task posting APIs have moved to post_task.h. See web_task_traits.h.
+
+  // TODO(crbug.com/878356): Consider replacing callsites of this with
+  // base::CreateTaskRunnerWithTraits({id})->DeleteSoon(..).
+  template <class T>
+  static bool DeleteSoon(ID identifier,
+                         const base::Location& from_here,
+                         const T* object) {
+    return GetTaskRunnerForThread(identifier)->DeleteSoon(from_here, object);
+  }
+
+  // Callable on any thread.  Returns whether the given well-known thread is
+  // initialized.
+  static bool IsThreadInitialized(ID identifier) WARN_UNUSED_RESULT;
+
+  // Callable on any thread.  Returns whether execution is currently on the
+  // given thread.  To DCHECK this, use the DCHECK_CURRENTLY_ON() macro above.
+  static bool CurrentlyOn(ID identifier) WARN_UNUSED_RESULT;
+
+  // If the current message loop is one of the known threads, returns true and
+  // sets identifier to its ID.
+  static bool GetCurrentThreadIdentifier(ID* identifier) WARN_UNUSED_RESULT;
+
+  // Sets the delegate for WebThread::IO.
+  //
+  // This only supports the IO thread.
+  //
+  // Only one delegate may be registered at a time. Delegates may be
+  // unregistered by providing a nullptr pointer.
+  //
+  // The delegate can only be registered through this call before
+  // WebThreadImpl(WebThread::IO) is created and unregistered after
+  // it was destroyed and its underlying thread shutdown.
+  static void SetIOThreadDelegate(WebThreadDelegate* delegate);
+
+  // Returns an appropriate error message for when DCHECK_CURRENTLY_ON() fails.
+  static std::string GetDCheckCurrentlyOnErrorMessage(ID expected);
+
+  // Use these templates in conjunction with RefCountedThreadSafe or
+  // std::unique_ptr when you want to ensure that an object is deleted on a
+  // specific thread. This is needed when an object can hop between threads
+  // (i.e. IO -> UI -> IO), and thread switching delays can mean that the final
+  // IO tasks executes before the UI task's stack unwinds. This would lead to
+  // the object destructing on the UI thread, which often is not what you want
+  // (i.e. to unregister from NotificationService, to notify other objects on
+  // the creating thread etc).
+  template <ID thread>
+  struct DeleteOnThread {
+    template <typename T>
+    static void Destruct(const T* x) {
+      if (CurrentlyOn(thread)) {
+        delete x;
+      } else {
+        if (!DeleteSoon(thread, FROM_HERE, x)) {
+          // Leaks at shutdown are acceptable under normal circumstances,
+          // do not report.
+        }
+      }
+    }
+    template <typename T>
+    inline void operator()(T* ptr) const {
+      enum { type_must_be_complete = sizeof(T) };
+      Destruct(ptr);
+    }
+  };
+
+  // Sample usage with RefCountedThreadSafe:
+  // class Foo
+  //     : public base::RefCountedThreadSafe<
+  //           Foo, web::WebThread::DeleteOnIOThread> {
+  //
+  // ...
+  //  private:
+  //   friend struct web::WebThread::DeleteOnThread<web::WebThread::IO>;
+  //   friend class base::DeleteHelper<Foo>;
+  //
+  //   ~Foo();
+  //
+  // Sample usage with std::unique_ptr:
+  // std::unique_ptr<Foo, web::WebThread::DeleteOnIOThread> ptr;
+  struct DeleteOnUIThread : public DeleteOnThread<UI> {};
+  struct DeleteOnIOThread : public DeleteOnThread<IO> {};
+
+ private:
+  friend class WebThreadImpl;
+
+  // For DeleteSoon() only.
+  static scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunnerForThread(
+      ID identifier);
+
+  WebThread() {}
+  DISALLOW_COPY_AND_ASSIGN(WebThread);
+};
+
+}  // namespace web
+
+#endif  // IOS_WEB_PUBLIC_THREAD_WEB_THREAD_H_
diff --git a/ios/web/public/thread/web_thread_delegate.h b/ios/web/public/thread/web_thread_delegate.h
new file mode 100644
index 0000000..4da12db5
--- /dev/null
+++ b/ios/web/public/thread/web_thread_delegate.h
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_PUBLIC_THREAD_WEB_THREAD_DELEGATE_H_
+#define IOS_WEB_PUBLIC_THREAD_WEB_THREAD_DELEGATE_H_
+
+namespace web {
+
+// WebThread::SetDelegate was deprecated, this is now only used by
+// WebThread::SetIOThreadDelegate.
+//
+// If registered as such, it will schedule to run Init() before the
+// message loop begins, and receive a CleanUp() call right after the message
+// loop ends (and before the WebThread has done its own clean-up).
+
+// A delegate for //web embedders to perform extra initialization/cleanup on
+// WebThread::IO.
+class WebThreadDelegate {
+ public:
+  virtual ~WebThreadDelegate() {}
+
+  // Called prior to completing initialization of WebThread::IO.
+  virtual void Init() = 0;
+
+  // Called during teardown of WebThread::IO.
+  virtual void CleanUp() = 0;
+};
+
+}  // namespace web
+
+#endif  // IOS_WEB_PUBLIC_THREAD_WEB_THREAD_DELEGATE_H_
diff --git a/ios/web/public/web_task_traits.h b/ios/web/public/web_task_traits.h
index fba59076..25266659 100644
--- a/ios/web/public/web_task_traits.h
+++ b/ios/web/public/web_task_traits.h
@@ -5,97 +5,6 @@
 #ifndef IOS_WEB_PUBLIC_WEB_TASK_TRAITS_H_
 #define IOS_WEB_PUBLIC_WEB_TASK_TRAITS_H_
 
-#include "base/task/task_traits.h"
-#include "base/task/task_traits_extension.h"
-#include "ios/web/public/web_thread.h"
-
-namespace web {
-
-// Tasks with this trait will not be executed inside a nested RunLoop.
-//
-// Note: This should rarely be required. Drivers of nested loops should instead
-// make sure to be reentrant when allowing nested application tasks (also rare).
-//
-// TODO(crbug.com/876272): Investigate removing this trait -- and any logic for
-// deferred tasks in MessageLoop.
-struct NonNestable {};
-
-// TaskTraits for running tasks on a WebThread.
-//
-// These traits enable the use of the //base/task/post_task.h APIs to post tasks
-// to a WebThread.
-//
-// To post a task to the UI thread (analogous for IO thread):
-//     base::PostTaskWithTraits(FROM_HERE, {WebThread::UI}, task);
-//
-// To obtain a TaskRunner for the UI thread (analogous for the IO thread):
-//     base::CreateSingleThreadTaskRunnerWithTraits({WebThread::UI});
-//
-// Tasks posted to the same WebThread with the same traits will be executed
-// in the order they were posted, regardless of the TaskRunners they were
-// posted via.
-//
-// See //base/task/post_task.h for more detailed documentation.
-//
-// Posting to a WebThread must only be done after it was initialized (ref.
-// WebMainLoop::CreateThreads() phase).
-class WebTaskTraitsExtension {
- public:
-  static constexpr uint8_t kExtensionId =
-      base::TaskTraitsExtensionStorage::kFirstEmbedderExtensionId;
-
-  struct ValidTrait : public base::TaskTraits::ValidTrait {
-    using base::TaskTraits::ValidTrait::ValidTrait;
-
-    ValidTrait(WebThread::ID);
-    ValidTrait(NonNestable);
-  };
-
-  template <
-      class... ArgTypes,
-      class CheckArgumentsAreValid = std::enable_if_t<
-          base::trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value>>
-  constexpr WebTaskTraitsExtension(ArgTypes... args)
-      : web_thread_(base::trait_helpers::GetEnum<WebThread::ID>(args...)),
-        nestable_(!base::trait_helpers::HasTrait<NonNestable>(args...)) {}
-
-  constexpr base::TaskTraitsExtensionStorage Serialize() const {
-    static_assert(8 == sizeof(WebTaskTraitsExtension),
-                  "Update Serialize() and Parse() when changing "
-                  "WebTaskTraitsExtension");
-    return {
-        kExtensionId,
-        {static_cast<uint8_t>(web_thread_), static_cast<uint8_t>(nestable_)}};
-  }
-
-  static const WebTaskTraitsExtension Parse(
-      const base::TaskTraitsExtensionStorage& extension) {
-    return WebTaskTraitsExtension(static_cast<WebThread::ID>(extension.data[0]),
-                                  static_cast<bool>(extension.data[1]));
-  }
-
-  constexpr WebThread::ID web_thread() const { return web_thread_; }
-
-  // Returns true if tasks with these traits may run in a nested RunLoop.
-  constexpr bool nestable() const { return nestable_; }
-
- private:
-  WebTaskTraitsExtension(WebThread::ID web_thread, bool nestable)
-      : web_thread_(web_thread), nestable_(nestable) {}
-
-  WebThread::ID web_thread_;
-  bool nestable_;
-};
-
-template <class... ArgTypes,
-          class = std::enable_if_t<base::trait_helpers::AreValidTraits<
-              WebTaskTraitsExtension::ValidTrait,
-              ArgTypes...>::value>>
-constexpr base::TaskTraitsExtensionStorage MakeTaskTraitsExtension(
-    ArgTypes&&... args) {
-  return WebTaskTraitsExtension(std::forward<ArgTypes>(args)...).Serialize();
-}
-
-}  // namespace web
+#include "ios/web/public/thread/web_task_traits.h"
 
 #endif  // IOS_WEB_PUBLIC_WEB_TASK_TRAITS_H_
diff --git a/ios/web/public/web_thread.h b/ios/web/public/web_thread.h
index cb056049..54eccd2 100644
--- a/ios/web/public/web_thread.h
+++ b/ios/web/public/web_thread.h
@@ -5,160 +5,6 @@
 #ifndef IOS_WEB_PUBLIC_WEB_THREAD_H_
 #define IOS_WEB_PUBLIC_WEB_THREAD_H_
 
-#include <string>
-#include <utility>
-
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
-#include "base/task_runner_util.h"
-
-namespace base {
-class Location;
-}
-
-namespace web {
-
-class WebThreadDelegate;
-
-// Use DCHECK_CURRENTLY_ON(WebThread::ID) to assert that a function can only be
-// called on the named WebThread.
-#define DCHECK_CURRENTLY_ON(thread_identifier)              \
-  (DCHECK(::web::WebThread::CurrentlyOn(thread_identifier)) \
-   << ::web::WebThread::GetDCheckCurrentlyOnErrorMessage(thread_identifier))
-
-///////////////////////////////////////////////////////////////////////////////
-// WebThread
-//
-// Utility functions for threads that are known by name. For example, there is
-// one IO thread for the entire process, and various pieces of code find it
-// useful to retrieve a pointer to the IO thread's message loop.
-//
-// See web_task_traits.h for posting Tasks to a WebThread.
-//
-// This class automatically handles the lifetime of different threads. You
-// should never need to cache pointers to MessageLoops, since they're not thread
-// safe.
-class WebThread {
- public:
-  // An enumeration of the well-known threads.
-  // NOTE: threads must be listed in the order of their life-time, with each
-  // thread outliving every other thread below it.
-  enum ID {
-    // The main thread in the browser.
-    UI,
-
-    // This is the thread that processes non-blocking IO, i.e. IPC and network.
-    // Blocking IO should happen in ThreadPool.
-    IO,
-
-    // NOTE: do not add new threads here. Instead you should just use
-    // base::Create*TaskRunnerWithTraits to run tasks on the ThreadPool.
-
-    // This identifier does not represent a thread.  Instead it counts the
-    // number of well-known threads.  Insert new well-known threads before this
-    // identifier.
-    ID_COUNT
-  };
-
-  // NOTE: Task posting APIs have moved to post_task.h. See web_task_traits.h.
-
-  // TODO(crbug.com/878356): Consider replacing callsites of this with
-  // base::CreateTaskRunnerWithTraits({id})->DeleteSoon(..).
-  template <class T>
-  static bool DeleteSoon(ID identifier,
-                         const base::Location& from_here,
-                         const T* object) {
-    return GetTaskRunnerForThread(identifier)->DeleteSoon(from_here, object);
-  }
-
-  // Callable on any thread.  Returns whether the given well-known thread is
-  // initialized.
-  static bool IsThreadInitialized(ID identifier) WARN_UNUSED_RESULT;
-
-  // Callable on any thread.  Returns whether execution is currently on the
-  // given thread.  To DCHECK this, use the DCHECK_CURRENTLY_ON() macro above.
-  static bool CurrentlyOn(ID identifier) WARN_UNUSED_RESULT;
-
-  // If the current message loop is one of the known threads, returns true and
-  // sets identifier to its ID.
-  static bool GetCurrentThreadIdentifier(ID* identifier) WARN_UNUSED_RESULT;
-
-  // Sets the delegate for WebThread::IO.
-  //
-  // This only supports the IO thread.
-  //
-  // Only one delegate may be registered at a time. Delegates may be
-  // unregistered by providing a nullptr pointer.
-  //
-  // The delegate can only be registered through this call before
-  // WebThreadImpl(WebThread::IO) is created and unregistered after
-  // it was destroyed and its underlying thread shutdown.
-  static void SetIOThreadDelegate(WebThreadDelegate* delegate);
-
-  // Returns an appropriate error message for when DCHECK_CURRENTLY_ON() fails.
-  static std::string GetDCheckCurrentlyOnErrorMessage(ID expected);
-
-  // Use these templates in conjunction with RefCountedThreadSafe or
-  // std::unique_ptr when you want to ensure that an object is deleted on a
-  // specific thread. This is needed when an object can hop between threads
-  // (i.e. IO -> UI -> IO), and thread switching delays can mean that the final
-  // IO tasks executes before the UI task's stack unwinds. This would lead to
-  // the object destructing on the UI thread, which often is not what you want
-  // (i.e. to unregister from NotificationService, to notify other objects on
-  // the creating thread etc).
-  template <ID thread>
-  struct DeleteOnThread {
-    template <typename T>
-    static void Destruct(const T* x) {
-      if (CurrentlyOn(thread)) {
-        delete x;
-      } else {
-        if (!DeleteSoon(thread, FROM_HERE, x)) {
-          // Leaks at shutdown are acceptable under normal circumstances,
-          // do not report.
-        }
-      }
-    }
-    template <typename T>
-    inline void operator()(T* ptr) const {
-      enum { type_must_be_complete = sizeof(T) };
-      Destruct(ptr);
-    }
-  };
-
-  // Sample usage with RefCountedThreadSafe:
-  // class Foo
-  //     : public base::RefCountedThreadSafe<
-  //           Foo, web::WebThread::DeleteOnIOThread> {
-  //
-  // ...
-  //  private:
-  //   friend struct web::WebThread::DeleteOnThread<web::WebThread::IO>;
-  //   friend class base::DeleteHelper<Foo>;
-  //
-  //   ~Foo();
-  //
-  // Sample usage with std::unique_ptr:
-  // std::unique_ptr<Foo, web::WebThread::DeleteOnIOThread> ptr;
-  struct DeleteOnUIThread : public DeleteOnThread<UI> {};
-  struct DeleteOnIOThread : public DeleteOnThread<IO> {};
-
- private:
-  friend class WebThreadImpl;
-
-  // For DeleteSoon() only.
-  static scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunnerForThread(
-      ID identifier);
-
-  WebThread() {}
-  DISALLOW_COPY_AND_ASSIGN(WebThread);
-};
-
-}  // namespace web
+#include "ios/web/public/thread/web_thread.h"
 
 #endif  // IOS_WEB_PUBLIC_WEB_THREAD_H_
diff --git a/ios/web/public/web_thread_delegate.h b/ios/web/public/web_thread_delegate.h
index f8005761..3fdf3fc 100644
--- a/ios/web/public/web_thread_delegate.h
+++ b/ios/web/public/web_thread_delegate.h
@@ -5,28 +5,6 @@
 #ifndef IOS_WEB_PUBLIC_WEB_THREAD_DELEGATE_H_
 #define IOS_WEB_PUBLIC_WEB_THREAD_DELEGATE_H_
 
-namespace web {
-
-// WebThread::SetDelegate was deprecated, this is now only used by
-// WebThread::SetIOThreadDelegate.
-//
-// If registered as such, it will schedule to run Init() before the
-// message loop begins, and receive a CleanUp() call right after the message
-// loop ends (and before the WebThread has done its own clean-up).
-
-// A delegate for //web embedders to perform extra initialization/cleanup on
-// WebThread::IO.
-class WebThreadDelegate {
- public:
-  virtual ~WebThreadDelegate() {}
-
-  // Called prior to completing initialization of WebThread::IO.
-  virtual void Init() = 0;
-
-  // Called during teardown of WebThread::IO.
-  virtual void CleanUp() = 0;
-};
-
-}  // namespace web
+#include "ios/web/public/thread/web_thread_delegate.h"
 
 #endif  // IOS_WEB_PUBLIC_WEB_THREAD_DELEGATE_H_
diff --git a/ios/web/security/certificate_policy_cache.cc b/ios/web/security/certificate_policy_cache.cc
index b91dff7..c216620 100644
--- a/ios/web/security/certificate_policy_cache.cc
+++ b/ios/web/security/certificate_policy_cache.cc
@@ -5,7 +5,7 @@
 #include "ios/web/public/security/certificate_policy_cache.h"
 
 #include "base/logging.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 
 namespace web {
 
diff --git a/ios/web/security/crw_cert_verification_controller.mm b/ios/web/security/crw_cert_verification_controller.mm
index 1c5be4a..58de6db 100644
--- a/ios/web/security/crw_cert_verification_controller.mm
+++ b/ios/web/security/crw_cert_verification_controller.mm
@@ -14,8 +14,8 @@
 #include "base/task/post_task.h"
 #include "ios/web/public/browser_state.h"
 #include "ios/web/public/security/certificate_policy_cache.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/security/wk_web_view_security_util.h"
 #include "net/cert/cert_verify_proc_ios.h"
 #include "net/cert/x509_util.h"
diff --git a/ios/web/security/crw_cert_verification_controller_unittest.mm b/ios/web/security/crw_cert_verification_controller_unittest.mm
index 8d7110f..ec1f61d 100644
--- a/ios/web/security/crw_cert_verification_controller_unittest.mm
+++ b/ios/web/security/crw_cert_verification_controller_unittest.mm
@@ -7,7 +7,7 @@
 #include "base/mac/foundation_util.h"
 #import "base/test/ios/wait_util.h"
 #include "ios/web/public/test/web_test.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/security/wk_web_view_security_util.h"
 #include "net/cert/x509_certificate.h"
 #include "net/cert/x509_util.h"
diff --git a/ios/web/service_manager_connection_impl.cc b/ios/web/service_manager_connection_impl.cc
index 68f9b8a..52883c7 100644
--- a/ios/web/service_manager_connection_impl.cc
+++ b/ios/web/service_manager_connection_impl.cc
@@ -15,7 +15,7 @@
 #include "base/no_destructor.h"
 #include "base/threading/thread_checker.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "services/service_manager/public/cpp/service.h"
diff --git a/ios/web/service_manager_connection_impl_unittest.cc b/ios/web/service_manager_connection_impl_unittest.cc
index 7c913a5d..c1807cb5 100644
--- a/ios/web/service_manager_connection_impl_unittest.cc
+++ b/ios/web/service_manager_connection_impl_unittest.cc
@@ -9,8 +9,8 @@
 #include "base/task/post_task.h"
 #include "base/test/bind_test_util.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "services/service_manager/public/cpp/constants.h"
 #include "services/service_manager/public/cpp/identity.h"
diff --git a/ios/web/service_manager_context.mm b/ios/web/service_manager_context.mm
index 14f8e5c..6b69f44 100644
--- a/ios/web/service_manager_context.mm
+++ b/ios/web/service_manager_context.mm
@@ -19,9 +19,9 @@
 #include "base/task/post_task.h"
 #include "ios/web/public/service_manager_connection.h"
 #include "ios/web/public/service_names.mojom.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/web_client.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
 #include "ios/web/service_manager_connection_impl.h"
 #import "ios/web/web_browser_manifest.h"
 #include "mojo/public/cpp/bindings/remote.h"
diff --git a/ios/web/session/session_certificate_policy_cache_impl.mm b/ios/web/session/session_certificate_policy_cache_impl.mm
index 194a72f..3d3ce057 100644
--- a/ios/web/session/session_certificate_policy_cache_impl.mm
+++ b/ios/web/session/session_certificate_policy_cache_impl.mm
@@ -8,8 +8,8 @@
 #include "base/task/post_task.h"
 #include "ios/web/public/security/certificate_policy_cache.h"
 #import "ios/web/public/session/crw_session_certificate_policy_cache_storage.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/web/session/session_certificate_policy_cache_impl_unittest.mm b/ios/web/session/session_certificate_policy_cache_impl_unittest.mm
index 9211e9e..b3a6159 100644
--- a/ios/web/session/session_certificate_policy_cache_impl_unittest.mm
+++ b/ios/web/session/session_certificate_policy_cache_impl_unittest.mm
@@ -11,8 +11,8 @@
 #import "ios/web/public/session/crw_session_certificate_policy_cache_storage.h"
 #include "ios/web/public/test/fakes/test_browser_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "net/cert/x509_certificate.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
diff --git a/ios/web/shell/shell_browser_state.mm b/ios/web/shell/shell_browser_state.mm
index 4b9278a..fcc3a96 100644
--- a/ios/web/shell/shell_browser_state.mm
+++ b/ios/web/shell/shell_browser_state.mm
@@ -9,8 +9,8 @@
 #include "base/path_service.h"
 #include "base/task/post_task.h"
 #include "base/threading/thread_restrictions.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web/shell/shell_url_request_context_getter.h"
 #include "services/test/user_id/user_id_service.h"
 
diff --git a/ios/web/thread/BUILD.gn b/ios/web/thread/BUILD.gn
new file mode 100644
index 0000000..cafa52d
--- /dev/null
+++ b/ios/web/thread/BUILD.gn
@@ -0,0 +1,16 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//ios/build/config.gni")
+
+source_set("thread") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  deps = [
+    "//ios/web/public",
+  ]
+
+  sources = [
+    "web_task_traits.cc",
+  ]
+}
diff --git a/ios/web/public/web_task_traits.cc b/ios/web/thread/web_task_traits.cc
similarity index 83%
rename from ios/web/public/web_task_traits.cc
rename to ios/web/thread/web_task_traits.cc
index fa85723..616f566 100644
--- a/ios/web/public/web_task_traits.cc
+++ b/ios/web/thread/web_task_traits.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 "ios/web/public/web_task_traits.h"
+#include "ios/web/public/thread/web_task_traits.h"
 
 namespace web {
 
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 0b1b2cc..558f126c 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -76,7 +76,7 @@
 #import "ios/web/public/deprecated/crw_native_content_provider.h"
 #include "ios/web/public/deprecated/url_verification_constants.h"
 #import "ios/web/public/download/download_controller.h"
-#include "ios/web/public/favicon_url.h"
+#include "ios/web/public/favicon/favicon_url.h"
 #import "ios/web/public/java_script_dialog_presenter.h"
 #include "ios/web/public/js_messaging/web_frame.h"
 #include "ios/web/public/js_messaging/web_frame_util.h"
diff --git a/ios/web/web_state/ui/favicon_util.h b/ios/web/web_state/ui/favicon_util.h
index c824fd5..97bc2eb 100644
--- a/ios/web/web_state/ui/favicon_util.h
+++ b/ios/web/web_state/ui/favicon_util.h
@@ -5,7 +5,7 @@
 #ifndef IOS_WEB_WEB_STATE_UI_FAVICON_UTIL_H_
 #define IOS_WEB_WEB_STATE_UI_FAVICON_UTIL_H_
 
-#include "ios/web/public/favicon_url.h"
+#include "ios/web/public/favicon/favicon_url.h"
 
 namespace base {
 class DictionaryValue;
diff --git a/ios/web/web_state/ui/favicon_util_unittest.mm b/ios/web/web_state/ui/favicon_util_unittest.mm
index 8c1346c3..108bca5 100644
--- a/ios/web/web_state/ui/favicon_util_unittest.mm
+++ b/ios/web/web_state/ui/favicon_util_unittest.mm
@@ -5,7 +5,7 @@
 #import "ios/web/web_state/ui/favicon_util.h"
 
 #include "base/values.h"
-#include "ios/web/public/favicon_url.h"
+#include "ios/web/public/favicon/favicon_url.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 46a41f4..f258d2dab 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -26,19 +26,19 @@
 #include "ios/web/public/browser_state.h"
 #import "ios/web/public/deprecated/crw_native_content.h"
 #import "ios/web/public/deprecated/crw_native_content_holder.h"
-#include "ios/web/public/favicon_url.h"
+#include "ios/web/public/favicon/favicon_url.h"
 #import "ios/web/public/java_script_dialog_presenter.h"
 #import "ios/web/public/navigation_item.h"
 #import "ios/web/public/session/crw_navigation_item_storage.h"
 #import "ios/web/public/session/crw_session_storage.h"
 #import "ios/web/public/session/serializable_user_data_manager.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_client.h"
 #import "ios/web/public/web_state/context_menu_params.h"
 #import "ios/web/public/web_state/web_state_delegate.h"
 #include "ios/web/public/web_state/web_state_interface_provider.h"
 #include "ios/web/public/web_state/web_state_observer.h"
 #import "ios/web/public/web_state/web_state_policy_decider.h"
-#include "ios/web/public/web_thread.h"
 #include "ios/web/public/webui/web_ui_ios_controller.h"
 #import "ios/web/security/web_interstitial_impl.h"
 #import "ios/web/session/session_certificate_policy_cache_impl.h"
diff --git a/ios/web/web_state/web_state_observer_bridge_unittest.mm b/ios/web/web_state/web_state_observer_bridge_unittest.mm
index eb5ded1..b6b109c 100644
--- a/ios/web/web_state/web_state_observer_bridge_unittest.mm
+++ b/ios/web/web_state/web_state_observer_bridge_unittest.mm
@@ -7,7 +7,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/scoped_observer.h"
 #import "ios/web/navigation/navigation_context_impl.h"
-#include "ios/web/public/favicon_url.h"
+#include "ios/web/public/favicon/favicon_url.h"
 #import "ios/web/public/test/fakes/crw_test_web_state_observer.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
diff --git a/ios/web/web_sub_thread.cc b/ios/web/web_sub_thread.cc
index 25e2c42..5780560 100644
--- a/ios/web/web_sub_thread.cc
+++ b/ios/web/web_sub_thread.cc
@@ -8,7 +8,7 @@
 #include "base/compiler_specific.h"
 #include "base/debug/alias.h"
 #include "base/threading/thread_restrictions.h"
-#include "ios/web/public/web_thread_delegate.h"
+#include "ios/web/public/thread/web_thread_delegate.h"
 #include "ios/web/web_thread_impl.h"
 #include "net/url_request/url_fetcher.h"
 
diff --git a/ios/web/web_sub_thread.h b/ios/web/web_sub_thread.h
index 4d8a26f..bea773c 100644
--- a/ios/web/web_sub_thread.h
+++ b/ios/web/web_sub_thread.h
@@ -8,7 +8,7 @@
 #include "base/macros.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_checker.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 
 namespace web {
 class WebThreadImpl;
diff --git a/ios/web/web_thread_impl.cc b/ios/web/web_thread_impl.cc
index a72971f..a8cc35a 100644
--- a/ios/web/web_thread_impl.cc
+++ b/ios/web/web_thread_impl.cc
@@ -19,8 +19,8 @@
 #include "base/task/post_task.h"
 #include "base/task/task_executor.h"
 #include "base/time/time.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread_delegate.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread_delegate.h"
 
 namespace web {
 
diff --git a/ios/web/web_thread_impl.h b/ios/web/web_thread_impl.h
index b0a2c61..5cd729d 100644
--- a/ios/web/web_thread_impl.h
+++ b/ios/web/web_thread_impl.h
@@ -8,7 +8,7 @@
 #include "base/callback.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/threading/thread.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 
 namespace web {
 
diff --git a/ios/web/web_thread_unittest.cc b/ios/web/web_thread_unittest.cc
index 0fb2f4f..f98df3b 100644
--- a/ios/web/web_thread_unittest.cc
+++ b/ios/web/web_thread_unittest.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 "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "base/bind.h"
 #include "base/task/post_task.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
-#include "ios/web/public/web_task_traits.h"
+#include "ios/web/public/thread/web_task_traits.h"
 #include "ios/web/web_thread_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
diff --git a/ios/web/webui/mojo_facade.mm b/ios/web/webui/mojo_facade.mm
index 4c5429c..4146e18d 100644
--- a/ios/web/webui/mojo_facade.mm
+++ b/ios/web/webui/mojo_facade.mm
@@ -19,8 +19,8 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/values.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/web_state/web_state.h"
-#include "ios/web/public/web_thread.h"
 #include "mojo/public/cpp/system/core.h"
 #include "services/service_manager/public/mojom/interface_provider.mojom.h"
 
diff --git a/ios/web/webui/url_data_manager_ios.cc b/ios/web/webui/url_data_manager_ios.cc
index 3415ac26..e430faa 100644
--- a/ios/web/webui/url_data_manager_ios.cc
+++ b/ios/web/webui/url_data_manager_ios.cc
@@ -17,8 +17,8 @@
 #include "base/synchronization/lock.h"
 #include "base/task/post_task.h"
 #include "ios/web/public/browser_state.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/webui/url_data_source_ios.h"
 #include "ios/web/webui/url_data_manager_ios_backend.h"
 #include "ios/web/webui/url_data_source_ios_impl.h"
diff --git a/ios/web/webui/url_data_manager_ios_backend.mm b/ios/web/webui/url_data_manager_ios_backend.mm
index bd1f3d2c..e73bc74 100644
--- a/ios/web/webui/url_data_manager_ios_backend.mm
+++ b/ios/web/webui/url_data_manager_ios_backend.mm
@@ -20,9 +20,9 @@
 #include "base/task/post_task.h"
 #include "base/trace_event/trace_event.h"
 #include "ios/web/public/browser_state.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web/public/web_client.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
 #include "ios/web/webui/shared_resources_data_source_ios.h"
 #include "ios/web/webui/url_data_source_ios_impl.h"
 #include "net/base/io_buffer.h"
diff --git a/ios/web/webui/url_data_source_ios_impl.cc b/ios/web/webui/url_data_source_ios_impl.cc
index 6488ade..8e9836ca 100644
--- a/ios/web/webui/url_data_source_ios_impl.cc
+++ b/ios/web/webui/url_data_source_ios_impl.cc
@@ -9,8 +9,8 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/strings/string_util.h"
 #include "base/task/post_task.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/webui/url_data_source_ios.h"
 #include "ios/web/webui/url_data_manager_ios_backend.h"
 
diff --git a/ios/web_view/internal/app/application_context.mm b/ios/web_view/internal/app/application_context.mm
index ed004d8..8c90ba5 100644
--- a/ios/web_view/internal/app/application_context.mm
+++ b/ios/web_view/internal/app/application_context.mm
@@ -17,7 +17,7 @@
 #include "components/proxy_config/pref_proxy_config_tracker_impl.h"
 #include "components/translate/core/browser/translate_download_manager.h"
 #include "components/variations/net/variations_http_headers.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web_view/cwv_web_view_buildflags.h"
 #include "ios/web_view/internal/app/web_view_io_thread.h"
 #import "ios/web_view/internal/cwv_flags_internal.h"
diff --git a/ios/web_view/internal/autofill/cwv_autofill_data_manager.mm b/ios/web_view/internal/autofill/cwv_autofill_data_manager.mm
index bbe026d..64ef7ca 100644
--- a/ios/web_view/internal/autofill/cwv_autofill_data_manager.mm
+++ b/ios/web_view/internal/autofill/cwv_autofill_data_manager.mm
@@ -10,8 +10,8 @@
 #include "base/task/post_task.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/personal_data_manager_observer.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web_view/internal/autofill/cwv_autofill_profile_internal.h"
 #import "ios/web_view/internal/autofill/cwv_credit_card_internal.h"
 #import "ios/web_view/public/cwv_autofill_data_manager_observer.h"
diff --git a/ios/web_view/internal/autofill/cwv_credit_card_verifier_unittest.mm b/ios/web_view/internal/autofill/cwv_credit_card_verifier_unittest.mm
index 66fa8b4..843095f 100644
--- a/ios/web_view/internal/autofill/cwv_credit_card_verifier_unittest.mm
+++ b/ios/web_view/internal/autofill/cwv_credit_card_verifier_unittest.mm
@@ -26,8 +26,8 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web_view/internal/autofill/cwv_credit_card_internal.h"
 #import "ios/web_view/public/cwv_credit_card_verifier_data_source.h"
 #import "ios/web_view/public/cwv_credit_card_verifier_delegate.h"
diff --git a/ios/web_view/internal/cwv_favicon_internal.h b/ios/web_view/internal/cwv_favicon_internal.h
index 9069c39..c680ea07 100644
--- a/ios/web_view/internal/cwv_favicon_internal.h
+++ b/ios/web_view/internal/cwv_favicon_internal.h
@@ -6,7 +6,7 @@
 #define IOS_WEB_VIEW_INTERNAL_CWV_FAVICON_INTERNAL_H_
 
 #include <vector>
-#include "ios/web/public/favicon_url.h"
+#include "ios/web/public/favicon/favicon_url.h"
 #import "ios/web_view/public/cwv_favicon.h"
 
 NS_ASSUME_NONNULL_BEGIN
diff --git a/ios/web_view/internal/cwv_favicon_unittest.mm b/ios/web_view/internal/cwv_favicon_unittest.mm
index a590d47..4066dd6d 100644
--- a/ios/web_view/internal/cwv_favicon_unittest.mm
+++ b/ios/web_view/internal/cwv_favicon_unittest.mm
@@ -7,7 +7,7 @@
 #import <UIKit/UIKit.h>
 #include <vector>
 
-#include "ios/web/public/favicon_url.h"
+#include "ios/web/public/favicon/favicon_url.h"
 #import "net/base/mac/url_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
diff --git a/ios/web_view/internal/cwv_web_view.mm b/ios/web_view/internal/cwv_web_view.mm
index 9647a6f..4fb07a90 100644
--- a/ios/web_view/internal/cwv_web_view.mm
+++ b/ios/web_view/internal/cwv_web_view.mm
@@ -17,7 +17,7 @@
 #include "components/language/ios/browser/ios_language_detection_tab_helper.h"
 #include "google_apis/google_api_keys.h"
 #import "ios/web/public/deprecated/crw_js_injection_receiver.h"
-#include "ios/web/public/favicon_url.h"
+#include "ios/web/public/favicon/favicon_url.h"
 #import "ios/web/public/js_messaging/web_frames_manager.h"
 #import "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
diff --git a/ios/web_view/internal/ios_global_state_web_view_configuration.mm b/ios/web_view/internal/ios_global_state_web_view_configuration.mm
index 0af3596..fd4473b 100644
--- a/ios/web_view/internal/ios_global_state_web_view_configuration.mm
+++ b/ios/web_view/internal/ios_global_state_web_view_configuration.mm
@@ -6,8 +6,8 @@
 
 #include "base/single_thread_task_runner.h"
 #include "base/task/post_task.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web_view/internal/web_view_global_state_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/web_view/internal/signin/web_view_identity_manager_factory.mm b/ios/web_view/internal/signin/web_view_identity_manager_factory.mm
index f0bc6774..0f7bc7b 100644
--- a/ios/web_view/internal/signin/web_view_identity_manager_factory.mm
+++ b/ios/web_view/internal/signin/web_view_identity_manager_factory.mm
@@ -14,8 +14,10 @@
 #include "components/signin/core/browser/account_consistency_method.h"
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
 #include "components/signin/core/browser/identity_manager_wrapper.h"
-#include "components/signin/core/browser/primary_account_policy_manager.h"
+#include "components/signin/core/browser/primary_account_manager.h"
+#include "components/signin/core/browser/primary_account_policy_manager_impl.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/signin_client.h"
 #include "components/signin/core/browser/signin_pref_names.h"
 #include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h"
 #include "ios/web_view/internal/app/application_context.h"
@@ -82,11 +84,13 @@
   pref_service->ClearPref(prefs::kGoogleServicesUsername);
   pref_service->ClearPref(prefs::kGoogleServicesUserAccountId);
 
-  std::unique_ptr<PrimaryAccountPolicyManager> service =
-      std::make_unique<PrimaryAccountPolicyManager>(
-          WebViewSigninClientFactory::GetForBrowserState(browser_state),
-          token_service, account_tracker_service,
-          signin::AccountConsistencyMethod::kDisabled);
+  SigninClient* client =
+      WebViewSigninClientFactory::GetForBrowserState(browser_state);
+  std::unique_ptr<PrimaryAccountManager> service =
+      std::make_unique<PrimaryAccountManager>(
+          client, token_service, account_tracker_service,
+          signin::AccountConsistencyMethod::kDisabled,
+          std::make_unique<PrimaryAccountPolicyManagerImpl>(client));
   service->Initialize(ApplicationContext::GetInstance()->GetLocalState());
   return service;
 }
diff --git a/ios/web_view/internal/sync/cwv_sync_controller.mm b/ios/web_view/internal/sync/cwv_sync_controller.mm
index 5842fea..0b1ff663 100644
--- a/ios/web_view/internal/sync/cwv_sync_controller.mm
+++ b/ios/web_view/internal/sync/cwv_sync_controller.mm
@@ -12,7 +12,7 @@
 #include "components/signin/core/browser/signin_error_controller.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/driver/sync_user_settings.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #import "ios/web_view/public/cwv_identity.h"
 #import "ios/web_view/public/cwv_sync_controller_data_source.h"
 #import "ios/web_view/public/cwv_sync_controller_delegate.h"
diff --git a/ios/web_view/internal/sync/web_view_gcm_profile_service_factory.mm b/ios/web_view/internal/sync/web_view_gcm_profile_service_factory.mm
index ebf00175..de9f73a 100644
--- a/ios/web_view/internal/sync/web_view_gcm_profile_service_factory.mm
+++ b/ios/web_view/internal/sync/web_view_gcm_profile_service_factory.mm
@@ -13,8 +13,8 @@
 #include "components/gcm_driver/gcm_client_factory.h"
 #include "components/gcm_driver/gcm_profile_service.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web_view/internal/app/application_context.h"
 #include "ios/web_view/internal/signin/web_view_identity_manager_factory.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
diff --git a/ios/web_view/internal/sync/web_view_profile_invalidation_provider_factory.mm b/ios/web_view/internal/sync/web_view_profile_invalidation_provider_factory.mm
index aab709d..c974505 100644
--- a/ios/web_view/internal/sync/web_view_profile_invalidation_provider_factory.mm
+++ b/ios/web_view/internal/sync/web_view_profile_invalidation_provider_factory.mm
@@ -19,8 +19,8 @@
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_registry.h"
+#include "ios/web/public/thread/web_task_traits.h"
 #include "ios/web/public/web_client.h"
-#include "ios/web/public/web_task_traits.h"
 #include "ios/web_view/internal/app/application_context.h"
 #include "ios/web_view/internal/signin/web_view_identity_manager_factory.h"
 #include "ios/web_view/internal/sync/web_view_gcm_profile_service_factory.h"
diff --git a/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm b/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
index 2a9af88..1bd0466 100644
--- a/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
+++ b/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
@@ -19,7 +19,7 @@
 #include "components/sync/driver/startup_controller.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/driver/sync_util.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web_view/internal/app/application_context.h"
 #include "ios/web_view/internal/autofill/web_view_personal_data_manager_factory.h"
 #include "ios/web_view/internal/passwords/web_view_password_store_factory.h"
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm
index 568be01..63f6eae8 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.mm
+++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -29,8 +29,8 @@
 #include "components/sync_user_events/user_event_service.h"
 #include "components/version_info/version_info.h"
 #include "components/version_info/version_string.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web_view/internal/autofill/web_view_personal_data_manager_factory.h"
 #include "ios/web_view/internal/passwords/web_view_password_store_factory.h"
 #include "ios/web_view/internal/pref_names.h"
diff --git a/ios/web_view/internal/web_view_browser_state.mm b/ios/web_view/internal/web_view_browser_state.mm
index 1899c00..0894bd1 100644
--- a/ios/web_view/internal/web_view_browser_state.mm
+++ b/ios/web_view/internal/web_view_browser_state.mm
@@ -29,8 +29,8 @@
 #include "components/sync_sessions/session_sync_prefs.h"
 #include "components/translate/core/browser/translate_pref_names.h"
 #include "components/translate/core/browser/translate_prefs.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web_view/cwv_web_view_buildflags.h"
 #include "ios/web_view/internal/autofill/web_view_personal_data_manager_factory.h"
 #include "ios/web_view/internal/content_settings/web_view_cookie_settings_factory.h"
diff --git a/ios/web_view/internal/web_view_early_page_script_provider.mm b/ios/web_view/internal/web_view_early_page_script_provider.mm
index f23fa61..2f91006 100644
--- a/ios/web_view/internal/web_view_early_page_script_provider.mm
+++ b/ios/web_view/internal/web_view_early_page_script_provider.mm
@@ -7,7 +7,7 @@
 #import <Foundation/Foundation.h>
 
 #include "ios/web/public/browser_state.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_thread.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/web_view/internal/web_view_web_client.mm b/ios/web_view/internal/web_view_web_client.mm
index 455245b..c1099d0b 100644
--- a/ios/web_view/internal/web_view_web_client.mm
+++ b/ios/web_view/internal/web_view_web_client.mm
@@ -13,9 +13,9 @@
 #include "components/ssl_errors/error_info.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/web/public/security/ssl_status.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/user_agent.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
 #import "ios/web_view/internal/cwv_ssl_status_internal.h"
 #import "ios/web_view/internal/cwv_web_view_internal.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
diff --git a/ios/web_view/internal/webdata_services/web_view_web_data_service_wrapper_factory.mm b/ios/web_view/internal/webdata_services/web_view_web_data_service_wrapper_factory.mm
index a08f7b4c..e859342 100644
--- a/ios/web_view/internal/webdata_services/web_view_web_data_service_wrapper_factory.mm
+++ b/ios/web_view/internal/webdata_services/web_view_web_data_service_wrapper_factory.mm
@@ -17,8 +17,8 @@
 #include "components/signin/core/browser/webdata/token_web_data.h"
 #include "components/sync/model/syncable_service.h"
 #include "components/webdata_services/web_data_service_wrapper.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread.h"
 #include "ios/web_view/internal/app/application_context.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 
diff --git a/media/gpu/linux/dmabuf_video_frame_pool.h b/media/gpu/linux/dmabuf_video_frame_pool.h
index c1679d6..cf920376 100644
--- a/media/gpu/linux/dmabuf_video_frame_pool.h
+++ b/media/gpu/linux/dmabuf_video_frame_pool.h
@@ -50,6 +50,12 @@
   // pool is exhausted will return a nullptr.
   virtual bool IsExhausted() = 0;
 
+  // Set the callback for notifying when the pool is no longer exhausted. The
+  // callback will be called on |parent_task_runner_|. Note: if there is a
+  // pending callback when calling NotifyWhenFrameAvailable(), the old callback
+  // would be dropped immediately.
+  virtual void NotifyWhenFrameAvailable(base::OnceClosure cb) = 0;
+
   // Returns the original frame of a wrapped frame. We need this method to
   // determine whether the frame returned by GetFrame() is the same one after
   // recycling, and bind destruction callback at original frames.
diff --git a/media/gpu/linux/platform_video_frame_pool.cc b/media/gpu/linux/platform_video_frame_pool.cc
index 2ec3304..b5a1ea5b 100644
--- a/media/gpu/linux/platform_video_frame_pool.cc
+++ b/media/gpu/linux/platform_video_frame_pool.cc
@@ -150,6 +150,9 @@
   base::AutoLock auto_lock(lock_);
 
   max_num_frames_ = max_num_frames;
+
+  if (frame_available_cb_ && !IsExhausted_Locked())
+    std::move(frame_available_cb_).Run();
 }
 
 void PlatformVideoFramePool::SetFrameFormat(VideoFrameLayout layout,
@@ -174,6 +177,13 @@
   DVLOGF(4);
   base::AutoLock auto_lock(lock_);
 
+  return IsExhausted_Locked();
+}
+
+bool PlatformVideoFramePool::IsExhausted_Locked() {
+  DVLOGF(4);
+  lock_.AssertAcquired();
+
   return free_frames_.empty() && GetTotalNumFrames_Locked() >= max_num_frames_;
 }
 
@@ -186,6 +196,18 @@
   return (it == frames_in_use_.end()) ? nullptr : it->second;
 }
 
+void PlatformVideoFramePool::NotifyWhenFrameAvailable(base::OnceClosure cb) {
+  DVLOGF(4);
+  base::AutoLock auto_lock(lock_);
+
+  if (!IsExhausted_Locked()) {
+    parent_task_runner_->PostTask(FROM_HERE, std::move(cb));
+    return;
+  }
+
+  frame_available_cb_ = std::move(cb);
+}
+
 // static
 void PlatformVideoFramePool::OnFrameReleasedThunk(
     base::Optional<base::WeakPtr<PlatformVideoFramePool>> pool,
@@ -216,6 +238,9 @@
                           origin_frame->natural_size())) {
     InsertFreeFrame_Locked(std::move(origin_frame));
   }
+
+  if (frame_available_cb_ && !IsExhausted_Locked())
+    std::move(frame_available_cb_).Run();
 }
 
 void PlatformVideoFramePool::InsertFreeFrame_Locked(
diff --git a/media/gpu/linux/platform_video_frame_pool.h b/media/gpu/linux/platform_video_frame_pool.h
index 4519a3a8e..a4dab7cd1 100644
--- a/media/gpu/linux/platform_video_frame_pool.h
+++ b/media/gpu/linux/platform_video_frame_pool.h
@@ -49,6 +49,7 @@
   scoped_refptr<VideoFrame> GetFrame() override;
   bool IsExhausted() override;
   VideoFrame* UnwrapFrame(const VideoFrame& wrapped_frame) override;
+  void NotifyWhenFrameAvailable(base::OnceClosure cb) override;
 
  private:
   friend class PlatformVideoFramePoolTest;
@@ -95,6 +96,7 @@
                            gfx::Rect visible_rect,
                            gfx::Size natural_size) const
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
+  bool IsExhausted_Locked() EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   // Purges the stale frame. This method is executed periodically on
   // |parent_task_runner_|.
@@ -126,6 +128,9 @@
   // The maximum number of frames created by the pool.
   size_t max_num_frames_ GUARDED_BY(lock_);
 
+  // Callback which is called when the pool is not exhausted.
+  base::OnceClosure frame_available_cb_ GUARDED_BY(lock_);
+
   // The weak pointer of this, bound at |parent_task_runner_|.
   // Used at the VideoFrame destruction callback.
   base::WeakPtr<PlatformVideoFramePool> weak_this_;
diff --git a/media/gpu/v4l2/v4l2_slice_video_decoder.cc b/media/gpu/v4l2/v4l2_slice_video_decoder.cc
index 1a29b23..fb6cc855 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decoder.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decoder.cc
@@ -749,15 +749,12 @@
     // We allocate the same number of output buffer slot in V4L2 device and the
     // output VideoFrame. If there is free output buffer slot but no free
     // VideoFrame, surface_it means the VideoFrame is not released at client
-    // side. Post PumpDecodeTask for busy waiting VideoFrame released.
-    //
-    // TODO(akahuang): WARNING: This is a temporary hack.
-    // Switch to event-driven mechanism instead of busy-polling.
+    // side. Post PumpDecodeTask when the pool has available frames.
     DVLOGF(3) << "There is no available VideoFrame.";
-    decoder_task_runner_->PostDelayedTask(
-        FROM_HERE,
-        base::BindOnce(&V4L2SliceVideoDecoder::PumpDecodeTask, weak_this_),
-        base::TimeDelta::FromMilliseconds(2));
+    frame_pool_->NotifyWhenFrameAvailable(base::BindOnce(
+        base::IgnoreResult(&base::SequencedTaskRunner::PostTask),
+        decoder_task_runner_, FROM_HERE,
+        base::BindOnce(&V4L2SliceVideoDecoder::PumpDecodeTask, weak_this_)));
     return nullptr;
   }
   frame->set_timestamp(current_decode_request_->buffer->timestamp());
@@ -765,8 +762,10 @@
   // Request V4L2 input and output buffers.
   V4L2WritableBufferRef input_buf = input_queue_->GetFreeBuffer();
   V4L2WritableBufferRef output_buf = output_queue_->GetFreeBuffer();
-  if (!input_buf.IsValid() || !output_buf.IsValid())
+  if (!input_buf.IsValid() || !output_buf.IsValid()) {
+    DVLOGF(3) << "There is no free V4L2 buffer.";
     return nullptr;
+  }
 
   // Record the frame and V4L2 buffers to the input and output records.
   int input_record_id = input_buf.BufferId();
diff --git a/mojo/core/channel_mac.cc b/mojo/core/channel_mac.cc
index 8820afe..1737269 100644
--- a/mojo/core/channel_mac.cc
+++ b/mojo/core/channel_mac.cc
@@ -353,8 +353,8 @@
         sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t) +
         (message->num_handles() * sizeof(mach_msg_port_descriptor_t));
     const size_t expected_message_size =
-        round_msg(mach_header_size + message->data_num_bytes() +
-                  sizeof(mach_msg_audit_trailer_t));
+        round_msg(mach_header_size + sizeof(uint64_t) +
+                  message->data_num_bytes() + sizeof(mach_msg_audit_trailer_t));
     const bool transfer_message_ool =
         expected_message_size >= send_buffer_.size();
 
diff --git a/mojo/core/channel_unittest.cc b/mojo/core/channel_unittest.cc
index 14db631..623ec6c 100644
--- a/mojo/core/channel_unittest.cc
+++ b/mojo/core/channel_unittest.cc
@@ -11,7 +11,9 @@
 #include "base/message_loop/message_loop.h"
 #include "base/optional.h"
 #include "base/process/process_handle.h"
+#include "base/process/process_metrics.h"
 #include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
 #include "mojo/core/platform_handle_utils.h"
@@ -508,6 +510,71 @@
   EXPECT_EQ(0u, delegate_b.error_count_);
 }
 
+class SingleMessageWaiterDelegate : public Channel::Delegate {
+ public:
+  SingleMessageWaiterDelegate() {}
+
+  void OnChannelMessage(const void* payload,
+                        size_t payload_size,
+                        std::vector<PlatformHandle> handles) override {
+    message_received_ = true;
+    run_loop_->Quit();
+  }
+
+  void OnChannelError(Channel::Error error) override {
+    channel_error_ = true;
+    run_loop_->Quit();
+  }
+
+  void Reset(base::RunLoop* loop) {
+    run_loop_ = loop;
+    message_received_ = false;
+    channel_error_ = false;
+  }
+
+  bool message_received() { return message_received_; }
+  bool channel_error() { return channel_error_; }
+
+ private:
+  bool message_received_ = false;
+  bool channel_error_ = false;
+  base::RunLoop* run_loop_;
+  DISALLOW_COPY_AND_ASSIGN(SingleMessageWaiterDelegate);
+};
+
+TEST(ChannelTest, MessageSizeTest) {
+  base::MessageLoop message_loop(base::MessageLoop::TYPE_IO);
+  PlatformChannel platform_channel;
+
+  SingleMessageWaiterDelegate receiver_delegate;
+  scoped_refptr<Channel> receiver = Channel::Create(
+      &receiver_delegate,
+      ConnectionParams(platform_channel.TakeLocalEndpoint()),
+      Channel::HandlePolicy::kAcceptHandles, message_loop.task_runner());
+  receiver->Start();
+
+  MockChannelDelegate sender_delegate;
+  scoped_refptr<Channel> sender = Channel::Create(
+      &sender_delegate, ConnectionParams(platform_channel.TakeRemoteEndpoint()),
+      Channel::HandlePolicy::kAcceptHandles, message_loop.task_runner());
+  sender->Start();
+
+  for (uint32_t i = 0; i < base::GetPageSize() * 4; ++i) {
+    SCOPED_TRACE(base::StringPrintf("message size %d", i));
+
+    auto message = std::make_unique<Channel::Message>(i, 0);
+    memset(message->mutable_payload(), 0xAB, i);
+    sender->Write(std::move(message));
+
+    base::RunLoop loop;
+    receiver_delegate.Reset(&loop);
+    loop.Run();
+
+    EXPECT_TRUE(receiver_delegate.message_received());
+    EXPECT_FALSE(receiver_delegate.channel_error());
+  }
+}
+
 }  // namespace
 }  // namespace core
 }  // namespace mojo
diff --git a/net/base/network_interfaces_win.cc b/net/base/network_interfaces_win.cc
index 6c3dde1..9629abac 100644
--- a/net/base/network_interfaces_win.cc
+++ b/net/base/network_interfaces_win.cc
@@ -103,11 +103,8 @@
 }
 
 WlanApi::WlanApi() : initialized(false) {
-  // Use an absolute path to load the DLL to avoid DLL preloading attacks.
-  static const wchar_t* const kDLL = L"%WINDIR%\\system32\\wlanapi.dll";
-  wchar_t path[MAX_PATH] = {0};
-  ExpandEnvironmentStrings(kDLL, path, base::size(path));
-  module = ::LoadLibraryEx(path, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
+  HMODULE module =
+      ::LoadLibraryEx(L"wlanapi.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
   if (!module)
     return;
 
diff --git a/services/identity/DEPS b/services/identity/DEPS
index 3345ad6..e000af0 100644
--- a/services/identity/DEPS
+++ b/services/identity/DEPS
@@ -8,7 +8,7 @@
   "+components/signin/core/browser/profile_oauth2_token_service.h",
   "+components/signin/core/browser/set_accounts_in_cookie_result.h",
   "+components/signin/core/browser/primary_account_manager.h",
-  "+components/signin/core/browser/primary_account_policy_manager.h",
+  "+components/signin/core/browser/primary_account_policy_manager_impl.h",
   "+components/signin/core/browser/test_signin_client.h",
   "+components/signin/public",
   "+components/sync_preferences/testing_pref_service_syncable.h",
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc
index 3f562c8c..6d148d4 100644
--- a/services/identity/public/cpp/identity_manager_unittest.cc
+++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -5,6 +5,8 @@
 #include "services/identity/public/cpp/identity_manager.h"
 
 #include <memory>
+#include <set>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -22,7 +24,8 @@
 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
 #include "components/signin/core/browser/list_accounts_test_utils.h"
-#include "components/signin/core/browser/primary_account_policy_manager.h"
+#include "components/signin/core/browser/primary_account_manager.h"
+#include "components/signin/core/browser/primary_account_policy_manager_impl.h"
 #include "components/signin/core/browser/set_accounts_in_cookie_result.h"
 #include "components/signin/core/browser/signin_switches.h"
 #include "components/signin/core/browser/test_signin_client.h"
@@ -34,7 +37,6 @@
 #include "services/identity/public/cpp/accounts_cookie_mutator_impl.h"
 #include "services/identity/public/cpp/accounts_mutator.h"
 #include "services/identity/public/cpp/diagnostics_provider_impl.h"
-#include "services/identity/public/cpp/identity_manager.h"
 #include "services/identity/public/cpp/identity_test_utils.h"
 #include "services/identity/public/cpp/primary_account_mutator.h"
 #include "services/identity/public/cpp/test_identity_manager_observer.h"
@@ -295,18 +297,16 @@
         &signin_client_, token_service.get(), account_tracker_service.get(),
         std::make_unique<image_fetcher::FakeImageDecoder>());
 
-#if defined(OS_CHROMEOS)
     DCHECK_EQ(account_consistency, signin::AccountConsistencyMethod::kDisabled)
         << "AccountConsistency is not used by PrimaryAccountManager";
+    std::unique_ptr<PrimaryAccountPolicyManager> policy_manager;
+#if !defined(OS_CHROMEOS)
+    policy_manager =
+        std::make_unique<PrimaryAccountPolicyManagerImpl>(&signin_client_);
+#endif
     auto primary_account_manager = std::make_unique<PrimaryAccountManager>(
         &signin_client_, token_service.get(), account_tracker_service.get(),
-        account_consistency);
-#else
-    auto primary_account_manager =
-        std::make_unique<PrimaryAccountPolicyManager>(
-            &signin_client_, token_service.get(), account_tracker_service.get(),
-            account_consistency);
-#endif
+        account_consistency, std::move(policy_manager));
 
     // Passing this switch ensures that the new PrimaryAccountManager starts
     // with a clean slate. Otherwise PrimaryAccountManager::Initialize will use
diff --git a/services/identity/public/cpp/identity_test_environment.cc b/services/identity/public/cpp/identity_test_environment.cc
index 3921f581..45ab54e 100644
--- a/services/identity/public/cpp/identity_test_environment.cc
+++ b/services/identity/public/cpp/identity_test_environment.cc
@@ -4,6 +4,11 @@
 
 #include "services/identity/public/cpp/identity_test_environment.h"
 
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -13,7 +18,8 @@
 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
 #include "components/signin/core/browser/identity_manager_wrapper.h"
-#include "components/signin/core/browser/primary_account_policy_manager.h"
+#include "components/signin/core/browser/primary_account_manager.h"
+#include "components/signin/core/browser/primary_account_policy_manager_impl.h"
 #include "components/signin/core/browser/test_signin_client.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "google_apis/gaia/oauth2_access_token_consumer.h"
@@ -198,16 +204,15 @@
       signin_client, token_service.get(), account_tracker_service.get(),
       std::make_unique<image_fetcher::FakeImageDecoder>());
 
+  std::unique_ptr<PrimaryAccountPolicyManager> policy_manager;
+#if !defined(OS_CHROMEOS)
+  policy_manager =
+      std::make_unique<PrimaryAccountPolicyManagerImpl>(signin_client);
+#endif
   std::unique_ptr<PrimaryAccountManager> primary_account_manager =
-#if defined(OS_CHROMEOS)
       std::make_unique<PrimaryAccountManager>(
           signin_client, token_service.get(), account_tracker_service.get(),
-          account_consistency);
-#else
-      std::make_unique<PrimaryAccountPolicyManager>(
-          signin_client, token_service.get(), account_tracker_service.get(),
-          account_consistency);
-#endif
+          account_consistency, std::move(policy_manager));
   primary_account_manager->Initialize(pref_service);
 
   std::unique_ptr<GaiaCookieManagerService> gaia_cookie_manager_service =
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index 954da001..2da9dc78 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -155,8 +155,10 @@
     return;
   }
 
-  for (const auto& name : removed_headers)
+  for (const auto& name : removed_headers) {
     request_.headers.RemoveHeader(name);
+    request_.cors_exempt_headers.RemoveHeader(name);
+  }
   request_.headers.MergeFrom(modified_headers);
 
   const std::string original_method = std::move(request_.method);
diff --git a/services/network/cors/cors_url_loader_unittest.cc b/services/network/cors/cors_url_loader_unittest.cc
index a7c14f5..cc35cd9c 100644
--- a/services/network/cors/cors_url_loader_unittest.cc
+++ b/services/network/cors/cors_url_loader_unittest.cc
@@ -49,6 +49,8 @@
 
 const uint32_t kRendererProcessId = 573;
 
+constexpr char kTestCorsExemptHeader[] = "x-test-cors-exempt";
+
 class TestURLLoaderFactory : public mojom::URLLoaderFactory {
  public:
   TestURLLoaderFactory() : weak_factory_(this) {}
@@ -158,6 +160,7 @@
     auto context_params = mojom::NetworkContextParams::New();
     context_params->initial_proxy_config =
         net::ProxyConfigWithAnnotation::CreateDirect();
+    context_params->cors_exempt_header_list.push_back(kTestCorsExemptHeader);
     network_context_ = std::make_unique<NetworkContext>(
         network_service_.get(), mojo::MakeRequest(&network_context_ptr_),
         std::move(context_params));
@@ -218,11 +221,10 @@
     test_url_loader_factory_->NotifyClientOnComplete(error_code);
   }
 
-  void FollowRedirect() {
+  void FollowRedirect(const std::vector<std::string>& removed_headers = {}) {
     DCHECK(url_loader_);
-    url_loader_->FollowRedirect({},              // removed_headers
-                                {},              // modified_headers
-                                base::nullopt);  // new_url
+    url_loader_->FollowRedirect(removed_headers, {} /*modified_headers*/,
+                                base::nullopt /*new_url*/);
   }
 
   const ResourceRequest& GetRequest() const {
@@ -1187,6 +1189,34 @@
   EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
 }
 
+TEST_F(CorsURLLoaderTest, CorsExemptHeaderRemovalOnCrossOriginRedirects) {
+  ResourceRequest request;
+  request.url = GURL("https://example.com/foo.png");
+  request.request_initiator = url::Origin::Create(GURL("https://example.com"));
+  request.fetch_request_mode = mojom::FetchRequestMode::kCors;
+  request.cors_exempt_headers.SetHeader(kTestCorsExemptHeader, "test-value");
+  CreateLoaderAndStart(request);
+  EXPECT_EQ(1, num_created_loaders());
+
+  NotifyLoaderClientOnReceiveRedirect(
+      CreateRedirectInfo(301, "GET", GURL("https://google.com/bar.png")));
+  RunUntilRedirectReceived();
+
+  EXPECT_TRUE(IsNetworkLoaderStarted());
+  ASSERT_TRUE(client().has_received_redirect());
+  ASSERT_FALSE(client().has_received_response());
+  ASSERT_FALSE(client().has_received_completion());
+  EXPECT_TRUE(
+      GetRequest().cors_exempt_headers.HasHeader(kTestCorsExemptHeader));
+
+  FollowRedirect({kTestCorsExemptHeader});
+  RunUntilCreateLoaderAndStartCalled();
+
+  EXPECT_EQ(2, num_created_loaders());
+  EXPECT_FALSE(
+      GetRequest().cors_exempt_headers.HasHeader(kTestCorsExemptHeader));
+}
+
 // Tests if OriginAccessList is actually used to decide the cors flag.
 // Details for the OriginAccessList behaviors are verified in
 // OriginAccessListTest, but this test intends to verify if CorsURlLoader calls
diff --git a/third_party/android_deps/libs/com_google_ar_core/README.chromium b/third_party/android_deps/libs/com_google_ar_core/README.chromium
index 253f7971..067103d 100644
--- a/third_party/android_deps/libs/com_google_ar_core/README.chromium
+++ b/third_party/android_deps/libs/com_google_ar_core/README.chromium
@@ -10,4 +10,4 @@
 
 
 Local Modifications:
-No modifications.
+Updated some proguard flags. The same proguard flag changes have been submitted to AR core directly and should be in any version >=1.11.
diff --git a/third_party/android_deps/libs/com_google_ar_core/com_google_ar_core.info b/third_party/android_deps/libs/com_google_ar_core/com_google_ar_core.info
index 88ab94a0..b28fe54 100644
--- a/third_party/android_deps/libs/com_google_ar_core/com_google_ar_core.info
+++ b/third_party/android_deps/libs/com_google_ar_core/com_google_ar_core.info
@@ -8,7 +8,7 @@
 has_proguard_flags = true
 has_r_text_file = true
 is_manifest_empty = false
-native_libraries = [ "jni/arm64-v8a/libarcore_sdk_c.so", "jni/arm64-v8a/libarcore_sdk_jni.so", "jni/armeabi-v7a/libarcore_sdk_c.so", "jni/armeabi-v7a/libarcore_sdk_jni.so", "jni/x86/libarcore_sdk_c.so", "jni/x86/libarcore_sdk_jni.so", "jni/x86_64/libarcore_sdk_c.so", "jni/x86_64/libarcore_sdk_jni.so" ]
-resources = [ "res/layout/__arcore_education.xml", "res/raw/keep.xml", "res/values-af/values.xml", "res/values-am/values.xml", "res/values-ar-rEG/values.xml", "res/values-ar-rSA/values.xml", "res/values-ar-rXB/values.xml", "res/values-az/values.xml", "res/values-b+es+419/values.xml", "res/values-b+sr+Latn/values.xml", "res/values-be/values.xml", "res/values-bg/values.xml", "res/values-bn/values.xml", "res/values-bs/values.xml", "res/values-ca/values.xml", "res/values-cs/values.xml", "res/values-da/values.xml", "res/values-de-rAT/values.xml", "res/values-de-rCH/values.xml", "res/values-de/values.xml", "res/values-el/values.xml", "res/values-en-rAU/values.xml", "res/values-en-rCA/values.xml", "res/values-en-rGB/values.xml", "res/values-en-rIE/values.xml", "res/values-en-rSG/values.xml", "res/values-en-rXA/values.xml", "res/values-en-rXC/values.xml", "res/values-en-rZA/values.xml", "res/values-es-rAR/values.xml", "res/values-es-rBO/values.xml", "res/values-es-rCL/values.xml", "res/values-es-rCO/values.xml", "res/values-es-rCR/values.xml", "res/values-es-rDO/values.xml", "res/values-es-rEC/values.xml", "res/values-es-rGT/values.xml", "res/values-es-rHN/values.xml", "res/values-es-rMX/values.xml", "res/values-es-rNI/values.xml", "res/values-es-rPA/values.xml", "res/values-es-rPE/values.xml", "res/values-es-rPR/values.xml", "res/values-es-rPY/values.xml", "res/values-es-rSV/values.xml", "res/values-es-rUS/values.xml", "res/values-es-rUY/values.xml", "res/values-es-rVE/values.xml", "res/values-es/values.xml", "res/values-et/values.xml", "res/values-eu/values.xml", "res/values-fa/values.xml", "res/values-fi/values.xml", "res/values-fil/values.xml", "res/values-fr-rCA/values.xml", "res/values-fr-rCH/values.xml", "res/values-fr/values.xml", "res/values-gl/values.xml", "res/values-gsw/values.xml", "res/values-gu/values.xml", "res/values-he/values.xml", "res/values-hi/values.xml", "res/values-hr/values.xml", "res/values-hu/values.xml", "res/values-hy/values.xml", "res/values-id/values.xml", "res/values-in/values.xml", "res/values-is/values.xml", "res/values-it/values.xml", "res/values-iw/values.xml", "res/values-ja/values.xml", "res/values-ka/values.xml", "res/values-kk/values.xml", "res/values-km/values.xml", "res/values-kn/values.xml", "res/values-ko/values.xml", "res/values-ky/values.xml", "res/values-lo/values.xml", "res/values-lt/values.xml", "res/values-lv/values.xml", "res/values-mk/values.xml", "res/values-ml/values.xml", "res/values-mn/values.xml", "res/values-mo/values.xml", "res/values-ms/values.xml", "res/values-my/values.xml", "res/values-nb/values.xml", "res/values-ne/values.xml", "res/values-nl/values.xml", "res/values-no/values.xml", "res/values-pa/values.xml", "res/values-pl/values.xml", "res/values-pt-rBR/values.xml", "res/values-pt-rPT/values.xml", "res/values-pt/values.xml", "res/values-ro/values.xml", "res/values-ru/values.xml", "res/values-si/values.xml", "res/values-sk/values.xml", "res/values-sl/values.xml", "res/values-sq/values.xml", "res/values-sr/values.xml", "res/values-sv/values.xml", "res/values-sw/values.xml", "res/values-ta/values.xml", "res/values-te/values.xml", "res/values-th/values.xml", "res/values-tl/values.xml", "res/values-tr/values.xml", "res/values-uk/values.xml", "res/values-ur/values.xml", "res/values-uz/values.xml", "res/values-vi/values.xml", "res/values-zh-rCN/values.xml", "res/values-zh-rHK/values.xml", "res/values-zh-rTW/values.xml", "res/values-zh/values.xml", "res/values-zu/values.xml", "res/values/values.xml" ]
+native_libraries = [ "jni/x86_64/libarcore_sdk_jni.so", "jni/x86_64/libarcore_sdk_c.so", "jni/armeabi-v7a/libarcore_sdk_jni.so", "jni/armeabi-v7a/libarcore_sdk_c.so", "jni/arm64-v8a/libarcore_sdk_jni.so", "jni/arm64-v8a/libarcore_sdk_c.so", "jni/x86/libarcore_sdk_jni.so", "jni/x86/libarcore_sdk_c.so" ]
+resources = [ "res/values-zu/values.xml", "res/values-fi/values.xml", "res/values-b+sr+Latn/values.xml", "res/values-it/values.xml", "res/values-ml/values.xml", "res/values-is/values.xml", "res/values-my/values.xml", "res/values-az/values.xml", "res/values-zh-rTW/values.xml", "res/values-mn/values.xml", "res/values-es-rPR/values.xml", "res/values-gl/values.xml", "res/values-iw/values.xml", "res/values-ca/values.xml", "res/values-be/values.xml", "res/values-fr-rCA/values.xml", "res/values-tl/values.xml", "res/values-lt/values.xml", "res/values-es-rNI/values.xml", "res/values-fil/values.xml", "res/values-el/values.xml", "res/values-bs/values.xml", "res/values-gu/values.xml", "res/values-hr/values.xml", "res/values-pt-rBR/values.xml", "res/values-id/values.xml", "res/values-en-rIE/values.xml", "res/values-sk/values.xml", "res/values-pa/values.xml", "res/values-bn/values.xml", "res/values-tr/values.xml", "res/layout/__arcore_education.xml", "res/values-ja/values.xml", "res/values-es-rUY/values.xml", "res/values-fr-rCH/values.xml", "res/values-sw/values.xml", "res/values-vi/values.xml", "res/values-kk/values.xml", "res/values-he/values.xml", "res/values-ur/values.xml", "res/values-no/values.xml", "res/values-es-rSV/values.xml", "res/values-ko/values.xml", "res/values-de/values.xml", "res/values-zh-rHK/values.xml", "res/values-uk/values.xml", "res/values-es/values.xml", "res/values-ar-rSA/values.xml", "res/values-sq/values.xml", "res/values-es-rVE/values.xml", "res/values-kn/values.xml", "res/values-mk/values.xml", "res/values-en-rAU/values.xml", "res/values-ka/values.xml", "res/values-en-rXA/values.xml", "res/values-ro/values.xml", "res/values-in/values.xml", "res/values-ky/values.xml", "res/values-da/values.xml", "res/values-es-rBO/values.xml", "res/values-zh-rCN/values.xml", "res/values-th/values.xml", "res/values/values.xml", "res/values-fa/values.xml", "res/values-hy/values.xml", "res/values-es-rPY/values.xml", "res/values-es-rHN/values.xml", "res/values-b+es+419/values.xml", "res/values-zh/values.xml", "res/values-eu/values.xml", "res/values-af/values.xml", "res/values-es-rMX/values.xml", "res/values-hi/values.xml", "res/values-hu/values.xml", "res/values-es-rDO/values.xml", "res/values-ms/values.xml", "res/values-si/values.xml", "res/values-lo/values.xml", "res/values-km/values.xml", "res/values-en-rXC/values.xml", "res/values-es-rGT/values.xml", "res/values-en-rZA/values.xml", "res/values-mo/values.xml", "res/values-lv/values.xml", "res/values-sv/values.xml", "res/values-pl/values.xml", "res/values-gsw/values.xml", "res/values-es-rEC/values.xml", "res/values-es-rPE/values.xml", "res/values-uz/values.xml", "res/values-te/values.xml", "res/values-sr/values.xml", "res/values-ne/values.xml", "res/values-ar-rXB/values.xml", "res/values-ru/values.xml", "res/values-de-rAT/values.xml", "res/values-bg/values.xml", "res/values-sl/values.xml", "res/values-cs/values.xml", "res/values-nb/values.xml", "res/values-en-rSG/values.xml", "res/values-am/values.xml", "res/values-en-rCA/values.xml", "res/values-ta/values.xml", "res/values-nl/values.xml", "res/values-pt-rPT/values.xml", "res/raw/keep.xml", "res/values-es-rUS/values.xml", "res/values-es-rAR/values.xml", "res/values-fr/values.xml", "res/values-es-rCL/values.xml", "res/values-ar-rEG/values.xml", "res/values-pt/values.xml", "res/values-en-rGB/values.xml", "res/values-de-rCH/values.xml", "res/values-es-rCR/values.xml", "res/values-es-rCO/values.xml", "res/values-et/values.xml", "res/values-es-rPA/values.xml" ]
 subjar_tuples = [  ]
 subjars = [  ]
diff --git a/third_party/blink/common/font_unique_name_lookup/font_table_matcher.cc b/third_party/blink/common/font_unique_name_lookup/font_table_matcher.cc
index ca36649..ea1db1d 100644
--- a/third_party/blink/common/font_unique_name_lookup/font_table_matcher.cc
+++ b/third_party/blink/common/font_unique_name_lookup/font_table_matcher.cc
@@ -77,4 +77,13 @@
   return intersection_result.empty();
 }
 
+void FontTableMatcher::SortUniqueNameTableForSearch(
+    FontUniqueNameTable* font_table) {
+  std::sort(font_table->mutable_name_map()->begin(),
+            font_table->mutable_name_map()->end(),
+            [](const auto& a, const auto& b) {
+              return a.font_name() < b.font_name();
+            });
+}
+
 }  // namespace blink
diff --git a/third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h b/third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h
index b29a0867..af7e0c87 100644
--- a/third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h
+++ b/third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h
@@ -54,6 +54,12 @@
   // their internal list of fonts is disjoint. Used only for testing.
   bool FontListIsDisjointFrom(const FontTableMatcher& other) const;
 
+  // When building a FontUniqueNameTable, use this function to prepare and sort
+  // the font names in the protobuf datastructure so that the binary search used
+  // by calls to MatchName succeeds on ReadOnlySharedMemoryMappings that are
+  // handed out to renderers.
+  static void SortUniqueNameTableForSearch(FontUniqueNameTable* font_table);
+
  private:
   FontUniqueNameTable font_table_;
 };
diff --git a/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h b/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h
index 2585814..389d2a9 100644
--- a/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h
+++ b/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h
@@ -61,9 +61,14 @@
 
   kIndexedDBConnection = 28,
 
+  // NB: This enum is used in a bitmask, so kMaxValue must be less than 64.
   kMaxValue = kIndexedDBConnection
 };
 
+static_assert(static_cast<uint32_t>(WebSchedulerTrackedFeature::kMaxValue) < 64,
+              "This enum is used in a bitmask, so the values should fit into a"
+              "64-bit integer");
+
 }  // namespace scheduler
 }  // namespace blink
 
diff --git a/third_party/blink/public/mojom/font_unique_name_lookup/font_unique_name_lookup.mojom b/third_party/blink/public/mojom/font_unique_name_lookup/font_unique_name_lookup.mojom
index e26d2c30..45fbf75 100644
--- a/third_party/blink/public/mojom/font_unique_name_lookup/font_unique_name_lookup.mojom
+++ b/third_party/blink/public/mojom/font_unique_name_lookup/font_unique_name_lookup.mojom
@@ -9,9 +9,23 @@
 
 interface FontUniqueNameLookup {
 
-  // Make the protobuf structured lookup list of
-  // (full_font_name|postscript_name) => (font_file + ttc_index) available to
-  // the renderer process.
-  [Sync] GetUniqueNameLookupTable() =>
-  (mojo_base.mojom.ReadOnlySharedMemoryRegion font_lookup_table);
+  // Synchronously returns a protobuf structured lookup list of
+  // (full_font_name|postscript_name) => (font_file + ttc_index) to the
+  // renderer process as a ReadOnlySharedMemoryRegion if it is available
+  // immediately without any blocking operations. Use FontTableMatcher to
+  // perform searches in it. If it is not available without blocking operations,
+  // sync_available is false and no shared memory region is provided.
+  [Sync]
+  GetUniqueNameLookupTableIfAvailable()
+      => (bool sync_available,
+          mojo_base.mojom.ReadOnlySharedMemoryRegion? font_lookup_table);
+
+  // Asynchronously returns a protobuf structured lookup list of
+  // (full_font_name|postscript_name) => (font_file + ttc_index) to the
+  // renderer process as a ReadOnlySharedMemoryRegion. The lookup list is built
+  // on the first renderer call to retrieving this list. Use FontTableMatcher
+  // to perform searches in it. Retrieval may take up to several seconds if the
+  // table needs rebuilding on browser side.
+  GetUniqueNameLookupTable() =>
+  (mojo_base.mojom.ReadOnlySharedMemoryRegion? font_lookup_table);
 };
diff --git a/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc b/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc
index f625692..c4e5bdc 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc
@@ -212,6 +212,17 @@
   v8::TryCatch try_catch(isolate);
   try_catch.SetVerbose(true);
 
+  if (RuntimeEnabledFeatures::ElementInternalsEnabled() && DisableShadow() &&
+      element.GetShadowRoot()) {
+    v8::Local<v8::Value> exception = V8ThrowDOMException::CreateOrEmpty(
+        script_state_->GetIsolate(), DOMExceptionCode::kNotSupportedError,
+        "The element already has a ShadowRoot though it is disabled by "
+        "disabledFeatures static field.");
+    if (!exception.IsEmpty())
+      V8ScriptRunner::ReportException(isolate, exception);
+    return false;
+  }
+
   Element* result = CallConstructor();
 
   // To report exception thrown from callConstructor()
diff --git a/third_party/blink/renderer/build/scripts/core/css/css_properties.py b/third_party/blink/renderer/build/scripts/core/css/css_properties.py
index c47048f..5b8a7add 100755
--- a/third_party/blink/renderer/build/scripts/core/css/css_properties.py
+++ b/third_party/blink/renderer/build/scripts/core/css/css_properties.py
@@ -205,7 +205,7 @@
         set_if_none(property_, 'inherited', False)
 
         # Initial function, Getters and Setters for ComputedStyle.
-        property_['initial'] = 'Initial' + method_name
+        set_if_none(property_, 'initial', 'Initial' + method_name)
         simple_type_name = str(property_['type_name']).split('::')[-1]
         set_if_none(property_, 'name_for_methods', method_name)
         set_if_none(property_, 'type_name', 'E' + method_name)
diff --git a/third_party/blink/renderer/build/scripts/core/css/properties/templates/style_builder_functions.tmpl b/third_party/blink/renderer/build/scripts/core/css/properties/templates/style_builder_functions.tmpl
index 7252bec..5a1fe08 100644
--- a/third_party/blink/renderer/build/scripts/core/css/properties/templates/style_builder_functions.tmpl
+++ b/third_party/blink/renderer/build/scripts/core/css/properties/templates/style_builder_functions.tmpl
@@ -253,31 +253,6 @@
   for (auto& listValue : To<CSSValueList>(value))
     data.{{vector}}.push_back(CSSToStyleMap::MapAnimation{{attribute}}(*listValue));
     {% endcall %}
-  {% elif property.style_builder_template == 'svg_paint' %}
-    {% set paint_type = property.style_builder_template_args['paint_type'] %}
-    {% set visited_link_setter = 'SetVisitedLink' + paint_type %}
-    {% call(property) apply_initial(property, header) %}
-  if (state.ApplyPropertyToRegularStyle())
-    {{set_value(property)}}(SVGComputedStyle::Initial{{paint_type}}());
-  if (state.ApplyPropertyToVisitedLinkStyle())
-    state.Style()->AccessSVGStyle().{{visited_link_setter}}(SVGComputedStyle::Initial{{paint_type}}());
-    {% endcall %}
-
-    {% call(property) apply_inherit(property, header) %}
-  const SVGComputedStyle& parent_svg_style = state.ParentStyle()->SvgStyle();
-  if (state.ApplyPropertyToRegularStyle())
-    {{set_value(property)}}(parent_svg_style.{{paint_type}}());
-  if (state.ApplyPropertyToVisitedLinkStyle())
-    state.Style()->AccessSVGStyle().{{visited_link_setter}}(parent_svg_style.{{paint_type}}());
-    {% endcall %}
-
-    {% call(property) apply_value(property, header) %}
-  SVGPaint paint = StyleBuilderConverter::{{property.converter}}(state, value);
-  if (state.ApplyPropertyToRegularStyle())
-    {{set_value(property)}}(paint);
-  if (state.ApplyPropertyToVisitedLinkStyle())
-    state.Style()->AccessSVGStyle().{{visited_link_setter}}(paint);
-    {% endcall %}
   {% elif property.style_builder_template in ['background_layer', 'mask_layer'] %}
     {% set layer_type = 'Background' if property.style_builder_template == 'background_layer' else 'Mask' %}
     {% set fill_type = property.style_builder_template_args['fill_type'] %}
@@ -340,36 +315,7 @@
     curr_child = curr_child->Next();
   }
     {% endcall %}
-  {% elif property.style_builder_template == 'color' %}
-    {% set initial_color = property.style_builder_template_args['initial_color'] or 'StyleColor::CurrentColor' %}
-    {% set visited_link_setter = 'SetVisitedLink' + property.name_for_methods %}
-    {% call(property) apply_initial(property, header) %}
-  StyleColor color = {{initial_color}}();
-  if (state.ApplyPropertyToRegularStyle())
-    {{set_value(property)}}(color);
-  if (state.ApplyPropertyToVisitedLinkStyle())
-    state.Style()->{{visited_link_setter}}(color);
-    {% endcall %}
-
-    {% call(property) apply_inherit(property, header) %}
-  // Visited link style can never explicitly inherit from parent visited link
-  // style so no separate getters are needed.
-  StyleColor color = state.ParentStyle()->{{property.getter}}();
-  if (state.ApplyPropertyToRegularStyle())
-    {{set_value(property)}}(color);
-  if (state.ApplyPropertyToVisitedLinkStyle())
-    state.Style()->{{visited_link_setter}}(color);
-    {% endcall %}
-
-    {% call(property) apply_value(property, header) %}
-  if (state.ApplyPropertyToRegularStyle())
-    {{set_value(property)}}(StyleBuilderConverter::{{property.converter}}(state, value));
-  if (state.ApplyPropertyToVisitedLinkStyle()) {
-    state.Style()->{{visited_link_setter}}(
-        StyleBuilderConverter::{{property.converter}}(state, value, true));
-  }
-    {% endcall %}
-  {% elif property.style_builder_template in ['color_only', 'visited_color'] %}
+  {% elif property.style_builder_template in ['color', 'visited_color'] %}
     {% set initial_color = property.style_builder_template_args['initial_color'] or 'StyleColor::CurrentColor' %}
     {% set is_visited = property.style_builder_template == 'visited_color' %}
     {% set main_getter = is_visited and property.unvisited_property.getter or property.getter %}
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 45e3759d..9c47e56 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -716,6 +716,10 @@
     "$blink_core_output_dir/css/properties/longhands/internal_visited_caret_color.h",
     "$blink_core_output_dir/css/properties/longhands/internal_visited_color.cc",
     "$blink_core_output_dir/css/properties/longhands/internal_visited_color.h",
+    "$blink_core_output_dir/css/properties/longhands/internal_visited_column_rule_color.cc",
+    "$blink_core_output_dir/css/properties/longhands/internal_visited_column_rule_color.h",
+    "$blink_core_output_dir/css/properties/longhands/internal_visited_outline_color.cc",
+    "$blink_core_output_dir/css/properties/longhands/internal_visited_outline_color.h",
     "$blink_core_output_dir/css/properties/longhands/internal_visited_text_decoration_color.cc",
     "$blink_core_output_dir/css/properties/longhands/internal_visited_text_decoration_color.h",
     "$blink_core_output_dir/css/properties/longhands/internal_visited_text_emphasis_color.cc",
diff --git a/third_party/blink/renderer/core/animation/animation_clock.cc b/third_party/blink/renderer/core/animation/animation_clock.cc
index fb1e29dc..b6e9bab 100644
--- a/third_party/blink/renderer/core/animation/animation_clock.cc
+++ b/third_party/blink/renderer/core/animation/animation_clock.cc
@@ -53,9 +53,9 @@
 }
 
 double AnimationClock::CurrentTime() {
-  if (monotonically_increasing_time_ &&
+  if (clock_ &&
       task_for_which_time_was_calculated_ != currently_running_task_) {
-    const base::TimeTicks current_time = monotonically_increasing_time_();
+    const base::TimeTicks current_time = clock_->NowTicks();
     if (time_ < current_time) {
       // Advance to the first estimated frame after the current time.
       const base::TimeDelta frame_shift =
diff --git a/third_party/blink/renderer/core/animation/animation_clock.h b/third_party/blink/renderer/core/animation/animation_clock.h
index 56eb03f..3261a17 100644
--- a/third_party/blink/renderer/core/animation/animation_clock.h
+++ b/third_party/blink/renderer/core/animation/animation_clock.h
@@ -34,9 +34,9 @@
 #include <limits>
 
 #include "base/macros.h"
+#include "base/time/default_tick_clock.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/time.h"
 
 namespace blink {
 
@@ -49,8 +49,8 @@
  public:
   using TimeTicksFunction = base::TimeTicks (*)();
   explicit AnimationClock(
-      TimeTicksFunction monotonically_increasing_time = WTF::CurrentTimeTicks)
-      : monotonically_increasing_time_(monotonically_increasing_time),
+      const base::TickClock* clock = base::DefaultTickClock::GetInstance())
+      : clock_(clock),
         time_(),
         task_for_which_time_was_calculated_(
             std::numeric_limits<unsigned>::max()) {}
@@ -58,16 +58,15 @@
   void UpdateTime(base::TimeTicks time);
   double CurrentTime();
   void ResetTimeForTesting(base::TimeTicks time = base::TimeTicks());
-  void DisableSyntheticTimeForTesting() {
-    monotonically_increasing_time_ = nullptr;
-  }
+  // The caller owns the |clock| which must outlive the AnimationClock.
+  void SetClockForTesting(const base::TickClock* clock) { clock_ = clock; }
 
   // notifyTaskStart should be called right before the main message loop starts
   // to run the next task from the message queue.
   static void NotifyTaskStart() { ++currently_running_task_; }
 
  private:
-  TimeTicksFunction monotonically_increasing_time_;
+  const base::TickClock* clock_;
   base::TimeTicks time_;
   unsigned task_for_which_time_was_calculated_;
   static unsigned currently_running_task_;
diff --git a/third_party/blink/renderer/core/animation/animation_clock_test.cc b/third_party/blink/renderer/core/animation/animation_clock_test.cc
index 0d186f87..3c6aadb 100644
--- a/third_party/blink/renderer/core/animation/animation_clock_test.cc
+++ b/third_party/blink/renderer/core/animation/animation_clock_test.cc
@@ -29,14 +29,15 @@
  */
 
 #include "third_party/blink/renderer/core/animation/animation_clock.h"
+#include "base/time/tick_clock.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
 
-class AnimationAnimationClockTest : public testing::Test {
+class AnimationAnimationClockTest : public testing::Test, base::TickClock {
  public:
-  AnimationAnimationClockTest() : animation_clock(MockTimeFunction) {}
+  AnimationAnimationClockTest() : animation_clock(this) {}
 
  protected:
   void SetUp() override {
@@ -44,16 +45,14 @@
     animation_clock.ResetTimeForTesting();
   }
 
-  static base::TimeTicks MockTimeFunction() {
+  base::TimeTicks NowTicks() const override {
     return base::TimeTicks() + base::TimeDelta::FromSecondsD(mock_time_);
   }
 
-  static double mock_time_;
+  double mock_time_;
   AnimationClock animation_clock;
 };
 
-double AnimationAnimationClockTest::mock_time_;
-
 TEST_F(AnimationAnimationClockTest, TimeIsGreaterThanZeroForUnitTests) {
   AnimationClock clock;
   // unit tests outside core/animation shouldn't need to do anything to get
diff --git a/third_party/blink/renderer/core/animation/animation_sim_test.cc b/third_party/blink/renderer/core/animation/animation_sim_test.cc
index 72d10464..a1ea9be3 100644
--- a/third_party/blink/renderer/core/animation/animation_sim_test.cc
+++ b/third_party/blink/renderer/core/animation/animation_sim_test.cc
@@ -37,7 +37,7 @@
   ScopedStackedCSSPropertyAnimationsForTest stacked_css_property_animation(
       true);
 
-  WebView().GetPage()->Animator().Clock().DisableSyntheticTimeForTesting();
+  WebView().GetPage()->Animator().Clock().SetClockForTesting(nullptr);
 
   SimRequest main_resource("https://example.com/", "text/html");
   LoadURL("https://example.com/");
diff --git a/third_party/blink/renderer/core/animation/color_property_functions.cc b/third_party/blink/renderer/core/animation/color_property_functions.cc
index 34c59dc..0c2b4df 100644
--- a/third_party/blink/renderer/core/animation/color_property_functions.cc
+++ b/third_party/blink/renderer/core/animation/color_property_functions.cc
@@ -82,9 +82,9 @@
     case CSSPropertyID::kColor:
       return style.InternalVisitedColor();
     case CSSPropertyID::kOutlineColor:
-      return style.VisitedLinkOutlineColor();
+      return style.InternalVisitedOutlineColor();
     case CSSPropertyID::kColumnRuleColor:
-      return style.VisitedLinkColumnRuleColor();
+      return style.InternalVisitedColumnRuleColor();
     case CSSPropertyID::kWebkitTextEmphasisColor:
       return style.InternalVisitedTextEmphasisColor();
     case CSSPropertyID::kWebkitTextFillColor:
@@ -189,7 +189,7 @@
       style.SetLightingColor(color);
       return;
     case CSSPropertyID::kOutlineColor:
-      style.SetVisitedLinkOutlineColor(color);
+      style.SetInternalVisitedOutlineColor(color);
       return;
     case CSSPropertyID::kStopColor:
       style.SetStopColor(color);
@@ -198,7 +198,7 @@
       style.SetInternalVisitedTextDecorationColor(color);
       return;
     case CSSPropertyID::kColumnRuleColor:
-      style.SetVisitedLinkColumnRuleColor(color);
+      style.SetInternalVisitedColumnRuleColor(color);
       return;
     case CSSPropertyID::kWebkitTextStrokeColor:
       style.SetInternalVisitedTextStrokeColor(color);
diff --git a/third_party/blink/renderer/core/animation/css/css_animations_test.cc b/third_party/blink/renderer/core/animation/css/css_animations_test.cc
index 2047d1e..e4e7e23 100644
--- a/third_party/blink/renderer/core/animation/css/css_animations_test.cc
+++ b/third_party/blink/renderer/core/animation/css/css_animations_test.cc
@@ -26,6 +26,7 @@
     platform()->AdvanceClockSeconds(1.);
     RenderingTest::SetUp();
     EnableCompositing();
+    SetUpAnimationClockForTesting();
   }
 
   void TearDown() override {
@@ -35,9 +36,12 @@
 
   void StartAnimationOnCompositor(Animation* animation) {
     static_cast<CompositorAnimationDelegate*>(animation)
-        ->NotifyAnimationStarted(
-            (CurrentTimeTicks() - base::TimeTicks()).InSecondsF(),
-            animation->CompositorGroup());
+        ->NotifyAnimationStarted(platform()
+                                     ->test_task_runner()
+                                     ->NowTicks()
+                                     .since_origin()
+                                     .InSecondsF(),
+                                 animation->CompositorGroup());
   }
 
   void AdvanceClockSeconds(double seconds) {
@@ -53,6 +57,17 @@
     return static_cast<const BasicComponentTransferFilterOperation*>(filter)
         ->Amount();
   }
+
+ private:
+  void SetUpAnimationClockForTesting() {
+    auto& animator_clock = GetPage().Animator().Clock();
+    animator_clock.SetClockForTesting(
+        platform()->test_task_runner()->GetMockTickClock());
+    animator_clock.ResetTimeForTesting();
+    // Call NofifyTaskStart() to force the computation of animation clock times
+    // after reset.
+    animator_clock.NotifyTaskStart();
+  }
 };
 
 // Verify that a composited animation is retargeted according to its composited
@@ -79,13 +94,15 @@
 
   // Starting the second transition should retarget the active transition.
   element->setAttribute(html_names::kClassAttr, "contrast2");
-  GetPage().Animator().ServiceScriptedAnimations(CurrentTimeTicks());
+  GetPage().Animator().ServiceScriptedAnimations(
+      platform()->test_task_runner()->NowTicks());
   UpdateAllLifecyclePhasesForTest();
   EXPECT_NEAR(0.6, GetContrastFilterAmount(element), 0.0000000001);
 
   // As it has been retargeted, advancing halfway should go to 0.3.
   AdvanceClockSeconds(0.5);
-  GetPage().Animator().ServiceScriptedAnimations(CurrentTimeTicks());
+  GetPage().Animator().ServiceScriptedAnimations(
+      platform()->test_task_runner()->NowTicks());
   UpdateAllLifecyclePhasesForTest();
   EXPECT_NEAR(0.3, GetContrastFilterAmount(element), 0.0000000001);
 }
@@ -113,6 +130,7 @@
   StartAnimationOnCompositor(animation);
   EXPECT_TRUE(animation->HasActiveAnimationsOnCompositor());
   AdvanceClockSeconds(0.003);
+  platform()->RunUntilIdle();
 
   // The computed style still contains no filter until the next frame.
   EXPECT_TRUE(element->GetComputedStyle()->Filter().IsEmpty());
diff --git a/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc
index 7ca959a3..e5b9a9a 100644
--- a/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc
@@ -133,11 +133,11 @@
   switch (CssProperty().PropertyID()) {
     case CSSPropertyID::kFill:
       mutable_svg_style.SetFillPaint(SVGPaint(color));
-      mutable_svg_style.SetVisitedLinkFillPaint(SVGPaint(color));
+      mutable_svg_style.SetInternalVisitedFillPaint(SVGPaint(color));
       break;
     case CSSPropertyID::kStroke:
       mutable_svg_style.SetStrokePaint(SVGPaint(color));
-      mutable_svg_style.SetVisitedLinkStrokePaint(SVGPaint(color));
+      mutable_svg_style.SetInternalVisitedStrokePaint(SVGPaint(color));
       break;
     default:
       NOTREACHED();
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index 4478259..9cc9d829 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -61,11 +61,6 @@
         "background_layer",
         "border_image",
         "color",
-        // The "color" template takes into account ApplyPropertyToRegularStyle
-        // and ApplyPropertyToVisitedStyle, whereas "color_only" unconditionally
-        // applies to the regular style.
-        // TODO(andruud): Remove those flags and rename this to just "color".
-        "color_only",
         "counter",
         "empty",
         "grid",
@@ -75,7 +70,6 @@
         "legacy",
         "mask_box",
         "mask_layer",
-        "svg_paint",
         "transition",
         "visited_color",
       ],
@@ -298,15 +292,21 @@
     // Tweaks how we choose defaults for getter, setter, initial and type_name.
     // For example, setting this to BlendMode will make us use a setter of
     // setBlendMode
+    // - initial
+    // The static function to invoke on ComputedStyleInitialValues,
+    // SVGComputedStyle, or FontBuilder to retrieve the initial value.
+    // Defaults to e.g. InitialBorderBottomLeft.
     // - getter
-    // The ComputedStyle getter, defaults to e.g. borderBottomLeft
+    // The ComputedStyle getter, defaults to e.g. BorderBottomLeft
     // - setter
-    // The ComputedStyle setter, defaults to e.g. setBorderBottomLeft
+    // The ComputedStyle setter, defaults to e.g. GetBorderBottomLeft
     // - type_name
     // The computed type for the property. Only required for the default value
     // application, defaults to e.g. EDisplay
     name_for_methods: {
     },
+    initial: {
+    },
     getter: {
     },
     setter: {
@@ -989,7 +989,7 @@
       keywords: ["currentcolor"],
       typedom_types: ["Keyword"],
       converter: "ConvertStyleColor",
-      style_builder_template: "color_only",
+      style_builder_template: "color",
       style_builder_template_args: {
         initial_color: "ComputedStyleInitialValues::InitialBackgroundColor",
       },
@@ -1085,7 +1085,7 @@
       keywords: ["currentcolor"],
       typedom_types: ["Keyword"],
       converter: "ConvertStyleColor",
-      style_builder_template: "color_only",
+      style_builder_template: "color",
       valid_for_visited_link: true,
     },
     {
@@ -1211,7 +1211,7 @@
       keywords: ["currentcolor"],
       typedom_types: ["Keyword"],
       converter: "ConvertStyleColor",
-      style_builder_template: "color_only",
+      style_builder_template: "color",
       valid_for_visited_link: true,
     },
     {
@@ -1254,7 +1254,7 @@
       keywords: ["currentcolor"],
       typedom_types: ["Keyword"],
       converter: "ConvertStyleColor",
-      style_builder_template: "color_only",
+      style_builder_template: "color",
       valid_for_visited_link: true,
     },
     {
@@ -1297,7 +1297,7 @@
       keywords: ["currentcolor"],
       typedom_types: ["Keyword"],
       converter: "ConvertStyleColor",
-      style_builder_template: "color_only",
+      style_builder_template: "color",
       valid_for_visited_link: true,
     },
     {
@@ -1672,12 +1672,10 @@
       interpolable: true,
       inherited: true,
       svg: true,
+      initial: "InitialFillPaint",
       setter: "SetFillPaint",
+      getter: "FillPaint",
       converter: "ConvertSVGPaint",
-      style_builder_template: "svg_paint",
-      style_builder_template_args: {
-        paint_type: "FillPaint",
-      },
       valid_for_visited_link: true,
     },
     {
@@ -3005,12 +3003,10 @@
       interpolable: true,
       inherited: true,
       svg: true,
+      initial: "InitialStrokePaint",
       setter: "SetStrokePaint",
+      getter: "StrokePaint",
       converter: "ConvertSVGPaint",
-      style_builder_template: "svg_paint",
-      style_builder_template_args: {
-        paint_type: "StrokePaint",
-      },
       valid_for_visited_link: true,
     },
     {
@@ -3162,7 +3158,7 @@
       keywords: ["currentcolor"],
       typedom_types: ["Keyword"],
       converter: "ConvertStyleColor",
-      style_builder_template: "color_only",
+      style_builder_template: "color",
       valid_for_visited_link: true,
     },
     {
@@ -3945,7 +3941,7 @@
       type_name: "Color",
       computed_style_custom_functions: ["getter", "setter"],
       converter: "ConvertStyleColor",
-      style_builder_template: "color_only",
+      style_builder_template: "color",
       valid_for_visited_link: true,
     },
     {
@@ -3976,7 +3972,7 @@
       type_name: "Color",
       computed_style_custom_functions: ["getter", "setter"],
       converter: "ConvertStyleColor",
-      style_builder_template: "color_only",
+      style_builder_template: "color",
       valid_for_visited_link: true,
     },
     {
@@ -4001,7 +3997,7 @@
       type_name: "Color",
       computed_style_custom_functions: ["getter", "setter"],
       converter: "ConvertStyleColor",
-      style_builder_template: "color_only",
+      style_builder_template: "color",
       valid_for_visited_link: true,
     },
     {
@@ -5179,6 +5175,19 @@
       },
     },
     {
+      name: "-internal-visited-column-rule-color",
+      visited_property_for: "column-rule-color",
+      property_methods: ["ColorIncludingFallback"],
+      field_group: "*->multi-col",
+      field_template: "external",
+      include_paths: ["third_party/blink/renderer/core/css/style_color.h"],
+      default_value: "StyleColor::CurrentColor()",
+      type_name: "StyleColor",
+      computed_style_custom_functions: ["getter","setter"],
+      converter: "ConvertStyleColor",
+      style_builder_template: "visited_color",
+    },
+    {
       name: "-internal-visited-background-color",
       visited_property_for: "background-color",
       property_methods: ["ColorIncludingFallback"],
@@ -5279,6 +5288,39 @@
       },
     },
     {
+      name: "-internal-visited-fill",
+      visited_property_for: "fill",
+      inherited: true,
+      svg: true,
+      initial: "InitialFillPaint",
+      setter: "SetInternalVisitedFillPaint",
+      getter: "FillPaint",
+      converter: "ConvertSVGPaint",
+    },
+    {
+      name: "-internal-visited-outline-color",
+      visited_property_for: "outline-color",
+      property_methods: ["ColorIncludingFallback"],
+      field_group: "*",
+      field_template: "external",
+      include_paths: ["third_party/blink/renderer/core/css/style_color.h"],
+      default_value: "StyleColor::CurrentColor()",
+      type_name: "StyleColor",
+      computed_style_custom_functions: ["getter", "setter"],
+      converter: "ConvertStyleColor",
+      style_builder_template: "visited_color",
+    },
+    {
+      name: "-internal-visited-stroke",
+      visited_property_for: "stroke",
+      inherited: true,
+      svg: true,
+      initial: "InitialStrokePaint",
+      setter: "SetInternalVisitedStrokePaint",
+      getter: "StrokePaint",
+      converter: "ConvertSVGPaint",
+    },
+    {
       name: "-internal-visited-text-decoration-color",
       visited_property_for: "text-decoration-color",
       property_methods: ["ColorIncludingFallback"],
diff --git a/third_party/blink/renderer/core/css/css_property_equality.cc b/third_party/blink/renderer/core/css/css_property_equality.cc
index 4c6f06260..367b339 100644
--- a/third_party/blink/renderer/core/css/css_property_equality.cc
+++ b/third_party/blink/renderer/core/css/css_property_equality.cc
@@ -142,8 +142,8 @@
       const SVGComputedStyle& a_svg = a.SvgStyle();
       const SVGComputedStyle& b_svg = b.SvgStyle();
       return a_svg.FillPaint().EqualTypeOrColor(b_svg.FillPaint()) &&
-             a_svg.VisitedLinkFillPaint().EqualTypeOrColor(
-                 b_svg.VisitedLinkFillPaint());
+             a_svg.InternalVisitedFillPaint().EqualTypeOrColor(
+                 b_svg.InternalVisitedFillPaint());
     }
     case CSSPropertyID::kFillOpacity:
       return a.FillOpacity() == b.FillOpacity();
@@ -222,7 +222,7 @@
       return a.Orphans() == b.Orphans();
     case CSSPropertyID::kOutlineColor:
       return a.OutlineColor() == b.OutlineColor() &&
-             a.VisitedLinkOutlineColor() == b.VisitedLinkOutlineColor();
+             a.InternalVisitedOutlineColor() == b.InternalVisitedOutlineColor();
     case CSSPropertyID::kOutlineOffset:
       return a.OutlineOffset() == b.OutlineOffset();
     case CSSPropertyID::kOutlineWidth:
@@ -251,8 +251,8 @@
       const SVGComputedStyle& a_svg = a.SvgStyle();
       const SVGComputedStyle& b_svg = b.SvgStyle();
       return a_svg.StrokePaint().EqualTypeOrColor(b_svg.StrokePaint()) &&
-             a_svg.VisitedLinkStrokePaint().EqualTypeOrColor(
-                 b_svg.VisitedLinkStrokePaint());
+             a_svg.InternalVisitedStrokePaint().EqualTypeOrColor(
+                 b_svg.InternalVisitedStrokePaint());
     }
     case CSSPropertyID::kStrokeDasharray:
       return a.StrokeDashArray() == b.StrokeDashArray();
@@ -298,7 +298,8 @@
       return a.RowGap() == b.RowGap();
     case CSSPropertyID::kColumnRuleColor:
       return a.ColumnRuleColor() == b.ColumnRuleColor() &&
-             a.VisitedLinkColumnRuleColor() == b.VisitedLinkColumnRuleColor();
+             a.InternalVisitedColumnRuleColor() ==
+                 b.InternalVisitedColumnRuleColor();
     case CSSPropertyID::kColumnRuleWidth:
       return a.ColumnRuleWidth() == b.ColumnRuleWidth();
     case CSSPropertyID::kColumnWidth:
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index e6421ab..652e394 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -180,6 +180,8 @@
 #include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_border_top_color.h"
 #include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_caret_color.h"
 #include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_color.h"
+#include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_column_rule_color.h"
+#include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_outline_color.h"
 #include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_text_decoration_color.h"
 #include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_text_emphasis_color.h"
 #include "third_party/blink/renderer/core/css/properties/longhands/internal_visited_text_fill_color.h"
@@ -2041,11 +2043,8 @@
 const blink::Color ColumnRuleColor::ColorIncludingFallback(
     bool visited_link,
     const ComputedStyle& style) const {
-  StyleColor result = visited_link ? style.VisitedLinkColumnRuleColor()
-                                   : style.ColumnRuleColor();
-  if (!result.IsCurrentColor())
-    return result.GetColor();
-  return visited_link ? style.InternalVisitedColor() : style.GetColor();
+  DCHECK(!visited_link);
+  return style.ColumnRuleColor().Resolve(style.GetColor());
 }
 
 const CSSValue* ColumnRuleColor::CSSValueFromComputedStyleInternal(
@@ -3740,6 +3739,22 @@
       style.InternalVisitedColor());
 }
 
+const blink::Color InternalVisitedColumnRuleColor::ColorIncludingFallback(
+    bool visited_link,
+    const ComputedStyle& style) const {
+  DCHECK(visited_link);
+  return style.InternalVisitedColumnRuleColor().Resolve(
+      style.InternalVisitedColor());
+}
+
+const blink::Color InternalVisitedOutlineColor::ColorIncludingFallback(
+    bool visited_link,
+    const ComputedStyle& style) const {
+  DCHECK(visited_link);
+  return style.InternalVisitedOutlineColor().Resolve(
+      style.InternalVisitedColor());
+}
+
 const blink::Color InternalVisitedTextDecorationColor::ColorIncludingFallback(
     bool visited_link,
     const ComputedStyle& style) const {
@@ -4614,11 +4629,8 @@
 const blink::Color OutlineColor::ColorIncludingFallback(
     bool visited_link,
     const ComputedStyle& style) const {
-  StyleColor result =
-      visited_link ? style.VisitedLinkOutlineColor() : style.OutlineColor();
-  if (!result.IsCurrentColor())
-    return result.GetColor();
-  return visited_link ? style.InternalVisitedColor() : style.GetColor();
+  DCHECK(!visited_link);
+  return style.OutlineColor().Resolve(style.GetColor());
 }
 
 const CSSValue* OutlineColor::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder.cc b/third_party/blink/renderer/core/css/resolver/style_builder.cc
index 0fe8784..5ff5c45 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder.cc
@@ -98,32 +98,6 @@
   // isInherit => (state.parentNode() && state.parentStyle())
   DCHECK(!is_inherit || (state.ParentNode() && state.ParentStyle()));
 
-  if (!property.IsVisited()) {
-    if (state.ApplyPropertyToVisitedLinkStyle()) {
-      if (const CSSProperty* visited = property.GetVisitedProperty()) {
-        ApplyProperty(*visited, state, value);
-        // Properties that support GetVisitedProperty() don't take the
-        // ApplyPropertyTo[Regular, VisitedLink]Style flags into account, so
-        // we can't proceed unless we _also_ want to apply the value to the
-        // regular style.
-        //
-        // TODO(andruud): Simplify this when all properties support
-        // GetVisitedProperty().
-        if (!state.ApplyPropertyToRegularStyle())
-          return;
-      }
-    }
-    // TODO(andruud): Simplify this when all properties support
-    // GetVisitedProperty().
-    if (!state.ApplyPropertyToRegularStyle() &&
-        (!state.ApplyPropertyToVisitedLinkStyle() ||
-         !property.IsValidForVisitedLink())) {
-      // Limit the properties that can be applied to only the ones honored by
-      // :visited.
-      return;
-    }
-  }
-
   if (is_inherit && !state.ParentStyle()->HasExplicitlyInheritedProperties() &&
       !is_inherited) {
     state.ParentStyle()->SetHasExplicitlyInheritedProperties();
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 b7ea55b..e94df1b 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -1170,11 +1170,6 @@
   if (state.AnimationUpdate().IsEmpty())
     return false;
 
-  if (state.Style()->InsideLink() != EInsideLink::kNotInsideLink) {
-    DCHECK(state.ApplyPropertyToRegularStyle());
-    state.SetApplyPropertyToVisitedLinkStyle(true);
-  }
-
   const ActiveInterpolationsMap& animations_map =
       state.AnimationUpdate().ActiveInterpolationsForStandardAnimations();
   const ActiveInterpolationsMap& transitions_map =
@@ -1193,8 +1188,6 @@
 
   DCHECK(!state.GetFontBuilder().FontDirty());
 
-  state.SetApplyPropertyToVisitedLinkStyle(false);
-
   return true;
 }
 
@@ -1454,14 +1447,26 @@
   return true;
 }
 
+static inline void ApplyProperty(const CSSProperty& property,
+                                 StyleResolverState& state,
+                                 const CSSValue& value,
+                                 unsigned apply_mask) {
+  if (apply_mask & kApplyMaskRegular)
+    StyleBuilder::ApplyProperty(property, state, value);
+  if (apply_mask & kApplyMaskVisited) {
+    if (const CSSProperty* visited = property.GetVisitedProperty())
+      StyleBuilder::ApplyProperty(*visited, state, value);
+  }
+}
+
 // This method expands the 'all' shorthand property to longhand properties
 // and applies the expanded longhand properties.
 template <CSSPropertyPriority priority>
-void StyleResolver::ApplyAllProperty(
-    StyleResolverState& state,
-    const CSSValue& all_value,
-    bool inherited_only,
-    ValidPropertyFilter valid_property_filter) {
+void StyleResolver::ApplyAllProperty(StyleResolverState& state,
+                                     const CSSValue& all_value,
+                                     bool inherited_only,
+                                     ValidPropertyFilter valid_property_filter,
+                                     unsigned apply_mask) {
   // The 'all' property doesn't apply to variables:
   // https://drafts.csswg.org/css-variables/#defining-variables
   if (priority == kResolveVariables)
@@ -1499,33 +1504,29 @@
     if (inherited_only && !property_class.IsInherited())
       continue;
 
-    StyleBuilder::ApplyProperty(property_class, state, all_value);
+    ApplyProperty(property_class, state, all_value, apply_mask);
   }
 }
 
 template <CSSPropertyPriority priority>
 static inline void ApplyProperty(
     const CSSPropertyValueSet::PropertyReference& reference,
-    StyleResolverState& state) {
+    StyleResolverState& state,
+    unsigned apply_mask) {
   static_assert(
       priority != kResolveVariables,
       "Application of custom properties must use specialized template");
   DCHECK_NE(reference.Id(), CSSPropertyID::kVariable);
-  StyleBuilder::ApplyProperty(reference.Property(), state, reference.Value());
+  ApplyProperty(reference.Property(), state, reference.Value(), apply_mask);
 }
 
 template <>
 inline void ApplyProperty<kResolveVariables>(
     const CSSPropertyValueSet::PropertyReference& reference,
-    StyleResolverState& state) {
+    StyleResolverState& state,
+    unsigned apply_mask) {
   CSSPropertyRef ref(reference.Name(), state.GetDocument());
-  StyleBuilder::ApplyProperty(ref.GetProperty(), state, reference.Value());
-}
-
-static bool WillApplyToVisitedLink(StyleResolverState& state,
-                                   const CSSProperty& property) {
-  return state.ApplyPropertyToVisitedLinkStyle() &&
-         (property.IsValidForVisitedLink() || property.GetVisitedProperty());
+  ApplyProperty(ref.GetProperty(), state, reference.Value(), apply_mask);
 }
 
 template <CSSPropertyPriority priority,
@@ -1535,7 +1536,8 @@
                                     bool is_important,
                                     bool inherited_only,
                                     NeedsApplyPass& needs_apply_pass,
-                                    ValidPropertyFilter valid_property_filter) {
+                                    ValidPropertyFilter valid_property_filter,
+                                    unsigned apply_mask) {
   unsigned property_count = properties->PropertyCount();
   for (unsigned i = 0; i < property_count; ++i) {
     CSSPropertyValueSet::PropertyReference current = properties->PropertyAt(i);
@@ -1549,7 +1551,7 @@
         needs_apply_pass.Set(kLowPropertyPriority, is_important);
       }
       ApplyAllProperty<priority>(state, current.Value(), inherited_only,
-                                 valid_property_filter);
+                                 valid_property_filter, apply_mask);
       continue;
     }
 
@@ -1570,18 +1572,33 @@
       // here. For this reason we don't allow declarations with explicitly
       // inherited properties to be cached.
       DCHECK(!current.Value().IsInheritedValue() ||
-             (!state.ApplyPropertyToRegularStyle() &&
-              !WillApplyToVisitedLink(state, current.Property())));
+             (!(apply_mask & kApplyMaskRegular) &&
+              (!(apply_mask & kApplyMaskVisited) ||
+               !current.Property().GetVisitedProperty())));
       continue;
     }
 
     if (!CSSPropertyPriorityData<priority>::PropertyHasPriority(property_id))
       continue;
 
-    ApplyProperty<priority>(current, state);
+    ApplyProperty<priority>(current, state, apply_mask);
   }
 }
 
+static inline unsigned ComputeApplyMask(
+    StyleResolverState& state,
+    const MatchedProperties& matched_properties) {
+  if (state.Style()->InsideLink() == EInsideLink::kNotInsideLink)
+    return kApplyMaskRegular;
+  static_assert(static_cast<int>(kApplyMaskRegular) ==
+                    static_cast<int>(CSSSelector::kMatchLink),
+                "kApplyMaskRegular and kMatchLink must match");
+  static_assert(static_cast<int>(kApplyMaskVisited) ==
+                    static_cast<int>(CSSSelector::kMatchVisited),
+                "kApplyMaskVisited and kMatchVisited must match");
+  return matched_properties.types_.link_match_type;
+}
+
 template <CSSPropertyPriority priority,
           StyleResolver::ShouldUpdateNeedsApplyPass shouldUpdateNeedsApplyPass>
 void StyleResolver::ApplyMatchedProperties(StyleResolverState& state,
@@ -1596,32 +1613,14 @@
       !needs_apply_pass.Get(priority, is_important))
     return;
 
-  if (state.Style()->InsideLink() != EInsideLink::kNotInsideLink) {
-    for (const auto& matched_properties : range) {
-      unsigned link_match_type = matched_properties.types_.link_match_type;
-      // FIXME: It would be nicer to pass these as arguments but that requires
-      // changes in many places.
-      state.SetApplyPropertyToRegularStyle(link_match_type &
-                                           CSSSelector::kMatchLink);
-      state.SetApplyPropertyToVisitedLinkStyle(link_match_type &
-                                               CSSSelector::kMatchVisited);
-
-      ApplyProperties<priority, shouldUpdateNeedsApplyPass>(
-          state, matched_properties.properties.Get(), is_important,
-          inherited_only, needs_apply_pass,
-          static_cast<ValidPropertyFilter>(
-              matched_properties.types_.valid_property_filter));
-    }
-    state.SetApplyPropertyToRegularStyle(true);
-    state.SetApplyPropertyToVisitedLinkStyle(false);
-    return;
-  }
   for (const auto& matched_properties : range) {
+    const unsigned apply_mask = ComputeApplyMask(state, matched_properties);
     ApplyProperties<priority, shouldUpdateNeedsApplyPass>(
         state, matched_properties.properties.Get(), is_important,
         inherited_only, needs_apply_pass,
         static_cast<ValidPropertyFilter>(
-            matched_properties.types_.valid_property_filter));
+            matched_properties.types_.valid_property_filter),
+        apply_mask);
   }
 }
 
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.h b/third_party/blink/renderer/core/css/resolver/style_resolver.h
index d00f5fe..f21181034 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.h
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.h
@@ -55,6 +55,7 @@
 class PropertyHandle;
 
 enum RuleMatchingBehavior { kMatchAllRules, kMatchAllRulesExcludingSMIL };
+enum ApplyMask { kApplyMaskRegular = 1 << 0, kApplyMaskVisited = 1 << 1 };
 
 // This class selects a ComputedStyle for a given element in a document based on
 // the document's collection of stylesheets (user styles, author styles, UA
@@ -256,7 +257,8 @@
                        bool is_important,
                        bool inherited_only,
                        NeedsApplyPass&,
-                       ValidPropertyFilter = ValidPropertyFilter::kNoFilter);
+                       ValidPropertyFilter,
+                       unsigned apply_mask);
   template <CSSPropertyPriority priority>
   void ApplyAnimatedStandardProperties(StyleResolverState&,
                                        const ActiveInterpolationsMap&);
@@ -264,7 +266,8 @@
   void ApplyAllProperty(StyleResolverState&,
                         const CSSValue&,
                         bool inherited_only,
-                        ValidPropertyFilter);
+                        ValidPropertyFilter,
+                        unsigned apply_mask);
 
   bool PseudoStyleForElementInternal(Element&,
                                      const PseudoStyleRequest&,
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
index 25c4156..947fbbd 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
@@ -43,8 +43,6 @@
       layout_parent_style_(layout_parent_style),
       is_animation_interpolation_map_ready_(false),
       is_animating_custom_properties_(false),
-      apply_property_to_regular_style_(true),
-      apply_property_to_visited_link_style_(false),
       has_dir_auto_attribute_(false),
       font_builder_(&document),
       element_style_resources_(GetElement(),
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_state.h b/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
index 68de630d..06a7533d 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
@@ -137,25 +137,6 @@
     return layout_parent_style_.get();
   }
 
-  // FIXME: These are effectively side-channel "out parameters" for the various
-  // map functions. When we map from CSS to style objects we use this state
-  // object to track various meta-data about that mapping (e.g. if it's
-  // cache-able).  We need to move this data off of StyleResolverState and
-  // closer to the objects it applies to. Possibly separating (immutable) inputs
-  // from (mutable) outputs.
-  void SetApplyPropertyToRegularStyle(bool is_apply) {
-    apply_property_to_regular_style_ = is_apply;
-  }
-  void SetApplyPropertyToVisitedLinkStyle(bool is_apply) {
-    apply_property_to_visited_link_style_ = is_apply;
-  }
-  bool ApplyPropertyToRegularStyle() const {
-    return apply_property_to_regular_style_;
-  }
-  bool ApplyPropertyToVisitedLinkStyle() const {
-    return apply_property_to_visited_link_style_;
-  }
-
   void CacheUserAgentBorderAndBackground();
 
   const CachedUAStyle* GetCachedUAStyle() const {
@@ -220,8 +201,6 @@
   bool is_animation_interpolation_map_ready_;
   bool is_animating_custom_properties_;
 
-  bool apply_property_to_regular_style_;
-  bool apply_property_to_visited_link_style_;
   bool has_dir_auto_attribute_;
 
   FontBuilder font_builder_;
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
index 9e40791..e861ed8f 100644
--- a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
+++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
@@ -40,8 +40,7 @@
     return "sha256-...";
   }
 
-  return "sha256-" + Base64Encode(reinterpret_cast<char*>(digest.data()),
-                                  digest.size(), kBase64DoNotInsertLFs);
+  return "sha256-" + Base64Encode(digest);
 }
 
 ContentSecurityPolicyHashAlgorithm ConvertHashAlgorithmToCSPHashAlgorithm(
diff --git a/third_party/blink/renderer/core/frame/use_counter_helper.cc b/third_party/blink/renderer/core/frame/use_counter_helper.cc
index 0e01512..cd959476 100644
--- a/third_party/blink/renderer/core/frame/use_counter_helper.cc
+++ b/third_party/blink/renderer/core/frame/use_counter_helper.cc
@@ -1261,6 +1261,10 @@
     case CSSPropertyID::kInternalVisitedBorderTopColor:
     case CSSPropertyID::kInternalVisitedCaretColor:
     case CSSPropertyID::kInternalVisitedColor:
+    case CSSPropertyID::kInternalVisitedColumnRuleColor:
+    case CSSPropertyID::kInternalVisitedFill:
+    case CSSPropertyID::kInternalVisitedOutlineColor:
+    case CSSPropertyID::kInternalVisitedStroke:
     case CSSPropertyID::kInternalVisitedTextDecorationColor:
     case CSSPropertyID::kInternalVisitedTextEmphasisColor:
     case CSSPropertyID::kInternalVisitedTextFillColor:
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
index bfad26f..06e5f5b 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
@@ -267,7 +267,6 @@
   scoped_refptr<AcceleratedStaticBitmapImage> bitmap =
       AcceleratedStaticBitmapImage::CreateFromSkImage(image,
                                                       context_provider_wrapper);
-  EXPECT_TRUE(bitmap->TextureHolderForTesting()->IsSkiaTextureHolder());
 
   ImageBitmap* image_bitmap = ImageBitmap::Create(bitmap);
   EXPECT_TRUE(image_bitmap);
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index 39afbf7..812bbd1 100644
--- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -6158,6 +6158,59 @@
       # String description of the GPU driver version.
       string driverVersion
 
+  # Describes the width and height dimensions of an entity.
+  type Size extends object
+    properties
+      # Width in pixels.
+      integer width
+      # Height in pixels.
+      integer height
+
+  # Describes a supported video decoding profile with its associated minimum and
+  # maximum resolutions.
+  type VideoDecodeAcceleratorCapability extends object
+    properties
+      # Video codec profile that is supported, e.g. VP9 Profile 2.
+      string profile
+      # Maximum video dimensions in pixels supported for this |profile|.
+      Size maxResolution
+      # Minimum video dimensions in pixels supported for this |profile|.
+      Size minResolution
+
+  # Describes a supported video encoding profile with its associated maximum
+  # resolution and maximum framerate.
+  type VideoEncodeAcceleratorCapability extends object
+    properties
+      # Video codec profile that is supported, e.g H264 Main.
+      string profile
+      # Maximum video dimensions in pixels supported for this |profile|.
+      Size maxResolution
+      # Maximum encoding framerate in frames per second supported for this
+      # |profile|, as fraction's numerator and denominator, e.g. 24/1 fps,
+      # 24000/1001 fps, etc.
+      integer maxFramerateNumerator
+      integer maxFramerateDenominator
+
+  # YUV subsampling type of the pixels of a given image.
+  type SubsamplingFormat extends string
+    enum
+      yuv420
+      yuv422
+      yuv444
+
+  # Describes a supported image decoding profile with its associated minimum and
+  # maximum resolutions and subsampling.
+  type ImageDecodeAcceleratorCapability extends object
+    properties
+      # Image coded, e.g. Jpeg.
+      string imageType
+      # Maximum supported dimensions of the image in pixels.
+      Size maxDimensions
+      # Minimum supported dimensions of the image in pixels.
+      Size minDimensions
+      # Optional array of supported subsampling formats, e.g. 4:2:0, if known.
+      array of SubsamplingFormat subsamplings
+
   # Provides information about the GPU(s) on the system.
   type GPUInfo extends object
     properties
@@ -6169,6 +6222,12 @@
       optional object featureStatus
       # An optional array of GPU driver bug workarounds.
       array of string driverBugWorkarounds
+      # Supported accelerated video decoding capabilities.
+      array of VideoDecodeAcceleratorCapability videoDecoding
+      # Supported accelerated video encoding capabilities.
+      array of VideoEncodeAcceleratorCapability videoEncoding
+      # Supported accelerated image decoding capabilities.
+      array of ImageDecodeAcceleratorCapability imageDecoding
 
   # Represents process info.
   type ProcessInfo extends object
diff --git a/third_party/blink/renderer/core/inspector/dom_patch_support.cc b/third_party/blink/renderer/core/inspector/dom_patch_support.cc
index 49384b0f..4caffa2 100644
--- a/third_party/blink/renderer/core/inspector/dom_patch_support.cc
+++ b/third_party/blink/renderer/core/inspector/dom_patch_support.cc
@@ -464,15 +464,14 @@
       attrs_digestor.Finish(digest_result);
       DCHECK(!attrs_digestor.has_failed());
       digest->attrs_sha1_ =
-          Base64Encode(reinterpret_cast<const char*>(digest_result.data()), 10);
+          Base64Encode(base::make_span(digest_result).first<10>());
       digestor.UpdateUtf8(digest->attrs_sha1_);
     }
   }
 
   digestor.Finish(digest_result);
   DCHECK(!digestor.has_failed());
-  digest->sha1_ =
-      Base64Encode(reinterpret_cast<const char*>(digest_result.data()), 10);
+  digest->sha1_ = Base64Encode(base::make_span(digest_result).first<10>());
 
   if (unused_nodes_map)
     unused_nodes_map->insert(digest->sha1_, digest);
diff --git a/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc b/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc
index 8eaf6a38..979936d 100644
--- a/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_animation_agent.cc
@@ -443,7 +443,7 @@
   DigestValue digest_result;
   digestor.Finish(digest_result);
   DCHECK(!digestor.has_failed());
-  return Base64Encode(reinterpret_cast<const char*>(digest_result.data()), 10);
+  return Base64Encode(base::make_span(digest_result).first<10>());
 }
 
 void InspectorAnimationAgent::DidCreateAnimation(unsigned sequence_number) {
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
index 710ab7a..2d6cb95 100644
--- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -426,9 +426,11 @@
       .setOpcode(op_code)
       .setMask(masked)
       // Only interpret the payload as UTF-8 when it's a text message
-      .setPayloadData(op_code == 1 ? String::FromUTF8WithLatin1Fallback(
-                                         payload, payload_length)
-                                   : Base64Encode(payload, payload_length))
+      .setPayloadData(
+          op_code == 1
+              ? String::FromUTF8WithLatin1Fallback(payload, payload_length)
+              : Base64Encode(
+                    base::as_bytes(base::make_span(payload, payload_length))))
       .build();
 }
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
index 339598b5..01ada15 100644
--- a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
@@ -245,7 +245,8 @@
     *result = text_content;
     *base64_encoded = false;
   } else if (buffer_data) {
-    *result = Base64Encode(buffer_data, buffer_size);
+    *result =
+        Base64Encode(base::as_bytes(base::make_span(buffer_data, buffer_size)));
     *base64_encoded = true;
   } else if (text_content.IsNull()) {
     *result = "";
@@ -326,8 +327,8 @@
       return false;
 
     const SharedBuffer::DeprecatedFlatData flat_buffer(std::move(buffer));
-    *result = Base64Encode(flat_buffer.Data(),
-                           SafeCast<wtf_size_t>(flat_buffer.size()));
+    *result = Base64Encode(base::as_bytes(
+        base::make_span(flat_buffer.Data(), flat_buffer.size())));
     *base64_encoded = true;
     return true;
   }
diff --git a/third_party/blink/renderer/core/inspector/v8_inspector_string.cc b/third_party/blink/renderer/core/inspector/v8_inspector_string.cc
index 83f403fc..9eed0c2 100644
--- a/third_party/blink/renderer/core/inspector/v8_inspector_string.cc
+++ b/third_party/blink/renderer/core/inspector/v8_inspector_string.cc
@@ -139,9 +139,7 @@
 }  // namespace
 
 String Binary::toBase64() const {
-  return impl_ ? WTF::Base64Encode(reinterpret_cast<const char*>(impl_->data()),
-                                   impl_->size())
-               : String();
+  return impl_ ? Base64Encode(*impl_) : String();
 }
 
 // static
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
index 6e00a8e..a2ebfbb 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
@@ -91,8 +91,8 @@
     return false;
   if (text_fragment.TextContent()[text_fragment.EndOffset()] != ' ')
     return false;
-  const NGInlineBreakToken& break_token =
-      *To<NGInlineBreakToken>(line_box.PhysicalFragment().BreakToken());
+  const NGInlineBreakToken& break_token = *To<NGInlineBreakToken>(
+      To<NGPhysicalLineBoxFragment>(line_box.PhysicalFragment()).BreakToken());
   // TODO(yosin): We should support OOF fragments between |fragment_| and
   // break token.
   if (break_token.TextOffset() != text_fragment.EndOffset() + 1)
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index 9b9feab..3a7bc24c 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -1940,7 +1940,7 @@
   if (!container_builder_.BfcBlockOffset().has_value())
     return NoBreak;
 
-  const NGPhysicalFragment& physical_fragment =
+  const NGPhysicalContainerFragment& physical_fragment =
       layout_result.PhysicalFragment();
 
   // If we haven't used any space at all in the fragmentainer yet, we cannot
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
index 63131ad1..4743312 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -90,7 +90,7 @@
 
   NGBlockNode box(ToLayoutBox(GetLayoutObjectByElementId("box")));
 
-  scoped_refptr<const NGPhysicalFragment> fragment =
+  scoped_refptr<const NGPhysicalBoxFragment> fragment =
       RunBlockLayoutAlgorithm(box, space);
 
   EXPECT_EQ(PhysicalSize(30, 40), fragment->Size());
@@ -1772,7 +1772,7 @@
   NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
       WritingMode::kHorizontalTb, TextDirection::kLtr,
       LogicalSize(LayoutUnit(100), kIndefiniteSize), true);
-  scoped_refptr<const NGPhysicalFragment> fragment =
+  scoped_refptr<const NGPhysicalBoxFragment> fragment =
       RunBlockLayoutAlgorithm(container, space);
 
   EXPECT_EQ(LayoutUnit(kWidthChild2), fragment->Size().width);
@@ -1924,7 +1924,7 @@
       node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
 
   // We should only have one 150x200 fragment with no fragmentation.
-  scoped_refptr<const NGPhysicalFragment> fragment =
+  scoped_refptr<const NGPhysicalBoxFragment> fragment =
       RunBlockLayoutAlgorithm(node, space);
   EXPECT_EQ(PhysicalSize(150, 200), fragment->Size());
   ASSERT_TRUE(fragment->BreakToken()->IsFinished());
@@ -1951,7 +1951,7 @@
       LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
       node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
 
-  scoped_refptr<const NGPhysicalFragment> fragment =
+  scoped_refptr<const NGPhysicalBoxFragment> fragment =
       RunBlockLayoutAlgorithm(node, space);
   EXPECT_EQ(PhysicalSize(150, 200), fragment->Size());
   ASSERT_FALSE(fragment->BreakToken()->IsFinished());
@@ -1994,7 +1994,7 @@
       LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
       node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
 
-  scoped_refptr<const NGPhysicalFragment> fragment =
+  scoped_refptr<const NGPhysicalBoxFragment> fragment =
       RunBlockLayoutAlgorithm(node, space);
   EXPECT_EQ(PhysicalSize(150, 200), fragment->Size());
   ASSERT_FALSE(fragment->BreakToken()->IsFinished());
@@ -2059,7 +2059,7 @@
       LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
       node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
 
-  scoped_refptr<const NGPhysicalFragment> fragment =
+  scoped_refptr<const NGPhysicalBoxFragment> fragment =
       RunBlockLayoutAlgorithm(node, space);
   EXPECT_EQ(PhysicalSize(150, 200), fragment->Size());
   ASSERT_FALSE(fragment->BreakToken()->IsFinished());
@@ -2122,7 +2122,7 @@
       LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
       node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
 
-  scoped_refptr<const NGPhysicalFragment> fragment =
+  scoped_refptr<const NGPhysicalBoxFragment> fragment =
       RunBlockLayoutAlgorithm(node, space);
   EXPECT_EQ(PhysicalSize(150, 70), fragment->Size());
   ASSERT_FALSE(fragment->BreakToken()->IsFinished());
@@ -2188,7 +2188,7 @@
       LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
       node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
 
-  scoped_refptr<const NGPhysicalFragment> fragment =
+  scoped_refptr<const NGPhysicalBoxFragment> fragment =
       RunBlockLayoutAlgorithm(node, space);
   EXPECT_EQ(PhysicalSize(150, 50), fragment->Size());
   ASSERT_FALSE(fragment->BreakToken()->IsFinished());
@@ -2268,7 +2268,7 @@
 
   AdvanceToLayoutPhase();
 
-  scoped_refptr<const NGPhysicalFragment> fragment =
+  scoped_refptr<const NGPhysicalBoxFragment> fragment =
       RunBlockLayoutAlgorithm(node, space);
   EXPECT_EQ(PhysicalSize(150, 60), fragment->Size());
   ASSERT_TRUE(!fragment->BreakToken() || fragment->BreakToken()->IsFinished());
@@ -2280,7 +2280,9 @@
 
   // float2 should only have one fragment.
   EXPECT_EQ(PhysicalSize(60, 200), float2->Size());
-  ASSERT_TRUE(!float2->BreakToken() || float2->BreakToken()->IsFinished());
+  ASSERT_TRUE(float2->IsBox());
+  NGBreakToken* break_token = To<NGPhysicalBoxFragment>(float2)->BreakToken();
+  EXPECT_TRUE(!break_token || break_token->IsFinished());
 }
 
 // Tests that a float child inside a zero height block fragments correctly.
@@ -2316,7 +2318,7 @@
       LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
       node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
 
-  scoped_refptr<const NGPhysicalFragment> fragment =
+  scoped_refptr<const NGPhysicalBoxFragment> fragment =
       RunBlockLayoutAlgorithm(node, space);
   EXPECT_EQ(PhysicalSize(150, 50), fragment->Size());
   ASSERT_FALSE(fragment->BreakToken()->IsFinished());
@@ -2439,7 +2441,7 @@
       WritingMode::kHorizontalTb, TextDirection::kLtr,
       LogicalSize(LayoutUnit(1000), kIndefiniteSize));
 
-  scoped_refptr<const NGPhysicalFragment> fragment =
+  scoped_refptr<const NGPhysicalBoxFragment> fragment =
       RunBlockLayoutAlgorithm(node, space);
   EXPECT_EQ(PhysicalSize(200, 150), fragment->Size());
 
@@ -2475,7 +2477,7 @@
       WritingMode::kHorizontalTb, TextDirection::kLtr,
       LogicalSize(LayoutUnit(1000), kIndefiniteSize), false, true);
 
-  scoped_refptr<const NGPhysicalFragment> fragment =
+  scoped_refptr<const NGPhysicalBoxFragment> fragment =
       RunBlockLayoutAlgorithm(node, space);
   EXPECT_EQ(PhysicalSize(200, 10), fragment->Size());
 
@@ -2513,7 +2515,7 @@
       WritingMode::kHorizontalTb, TextDirection::kLtr,
       LogicalSize(LayoutUnit(1000), kIndefiniteSize), false, true);
 
-  scoped_refptr<const NGPhysicalFragment> fragment =
+  scoped_refptr<const NGPhysicalBoxFragment> fragment =
       RunBlockLayoutAlgorithm(node, space);
   EXPECT_EQ(PhysicalSize(200, 10), fragment->Size());
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
index cf3108c..21b54f6c 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -153,7 +153,7 @@
 }
 
 NGBoxFragmentBuilder& NGBoxFragmentBuilder::PropagateBreak(
-    const NGPhysicalFragment& child_fragment) {
+    const NGPhysicalContainerFragment& child_fragment) {
   DCHECK(has_block_fragmentation_);
   if (!did_break_) {
     const auto* token = child_fragment.BreakToken();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index d491b25..29ffa670 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -97,7 +97,7 @@
 
   // Update if we have fragmented in this flow.
   NGBoxFragmentBuilder& PropagateBreak(const NGLayoutResult&);
-  NGBoxFragmentBuilder& PropagateBreak(const NGPhysicalFragment&);
+  NGBoxFragmentBuilder& PropagateBreak(const NGPhysicalContainerFragment&);
 
   void AddOutOfFlowLegacyCandidate(NGBlockNode,
                                    const NGStaticPosition&,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
index e61ae6a5..9c556e34 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
@@ -17,12 +17,13 @@
                                     const NGPhysicalFragment& fragment) {
   if (!fragment.IsBox())
     return LayoutUnit();
-  const auto* break_token = To<NGBlockBreakToken>(fragment.BreakToken());
+  const NGPhysicalBoxFragment& box_fragment =
+      To<NGPhysicalBoxFragment>(fragment);
+  const auto* break_token = To<NGBlockBreakToken>(box_fragment.BreakToken());
   if (!break_token)
     return LayoutUnit();
   NGBoxFragment logical_fragment(constraint_space.GetWritingMode(),
-                                 constraint_space.Direction(),
-                                 To<NGPhysicalBoxFragment>(fragment));
+                                 constraint_space.Direction(), box_fragment);
   return break_token->UsedBlockSize() - logical_fragment.BlockSize();
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
index bc14ebb..31ead905 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 
@@ -34,7 +34,10 @@
 
 // Return true if the specified fragment is the final fragment of some node.
 inline bool IsLastFragment(const NGPhysicalFragment& fragment) {
-  const auto* break_token = fragment.BreakToken();
+  if (!fragment.IsContainer())
+    return false;
+  const auto* break_token =
+      To<NGPhysicalContainerFragment>(fragment).BreakToken();
   return !break_token || break_token->IsFinished();
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
index 52c4cc5a..7e60ee5 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
@@ -17,6 +17,7 @@
 namespace {
 
 struct SameSizeAsNGPhysicalContainerFragment : NGPhysicalFragment {
+  void* break_token;
   std::unique_ptr<Vector<NGOutOfFlowPositionedDescendant>>
       oof_positioned_descendants_;
   void* pointer;
@@ -36,6 +37,7 @@
     NGFragmentType type,
     unsigned sub_type)
     : NGPhysicalFragment(builder, type, sub_type),
+      break_token_(std::move(builder->break_token_)),
       oof_positioned_descendants_(
           builder->oof_positioned_descendants_.IsEmpty()
               ? nullptr
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
index b65ab45..de824de 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
@@ -8,6 +8,7 @@
 #include "base/containers/span.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_break_token.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_link.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
@@ -83,6 +84,8 @@
 
   ~NGPhysicalContainerFragment();
 
+  NGBreakToken* BreakToken() const { return break_token_.get(); }
+
   // Returns the children of |this|.
   //
   // Note, children in this collection maybe old generations. Items in this
@@ -150,6 +153,7 @@
 
   static bool DependsOnPercentageBlockSize(const NGContainerFragmentBuilder&);
 
+  scoped_refptr<NGBreakToken> break_token_;
   const std::unique_ptr<Vector<NGOutOfFlowPositionedDescendant>>
       oof_positioned_descendants_;
 
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 6cb1590..91742b4 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
@@ -12,7 +12,6 @@
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_break_token.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
@@ -24,7 +23,7 @@
 
 struct SameSizeAsNGPhysicalFragment
     : RefCounted<const NGPhysicalFragment, NGPhysicalFragmentTraits> {
-  void* pointers[2];
+  void* layout_object;
   PhysicalSize size;
   unsigned flags;
 };
@@ -221,7 +220,6 @@
                                        unsigned sub_type)
     : layout_object_(*builder->layout_object_),
       size_(ToPhysicalSize(builder->size_, builder->GetWritingMode())),
-      break_token_(std::move(builder->break_token_)),
       type_(type),
       sub_type_(sub_type),
       style_variant_((unsigned)builder->style_variant_),
@@ -235,11 +233,9 @@
                                        NGStyleVariant style_variant,
                                        PhysicalSize size,
                                        NGFragmentType type,
-                                       unsigned sub_type,
-                                       scoped_refptr<NGBreakToken> break_token)
+                                       unsigned sub_type)
     : layout_object_(*layout_object),
       size_(size),
-      break_token_(std::move(break_token)),
       type_(type),
       sub_type_(sub_type),
       style_variant_((unsigned)style_variant),
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
index 923cf278..8488674 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
@@ -11,7 +11,7 @@
 #include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_size.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_break_token.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_style_variant.h"
 #include "third_party/blink/renderer/platform/graphics/touch_action.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
@@ -21,10 +21,8 @@
 namespace blink {
 
 class ComputedStyle;
-class LayoutObject;
 class Node;
 class NGFragmentBuilder;
-class NGBreakToken;
 class NGInlineItem;
 class PaintLayer;
 
@@ -159,7 +157,6 @@
   // (0, 0).
   PhysicalRect LocalRect() const { return {{}, size_}; }
 
-  NGBreakToken* BreakToken() const { return break_token_.get(); }
   NGStyleVariant StyleVariant() const {
     return static_cast<NGStyleVariant>(style_variant_);
   }
@@ -278,8 +275,7 @@
                      NGStyleVariant,
                      PhysicalSize size,
                      NGFragmentType type,
-                     unsigned sub_type,
-                     scoped_refptr<NGBreakToken> break_token = nullptr);
+                     unsigned sub_type);
 
   const ComputedStyle& SlowEffectiveStyle() const;
 
@@ -287,7 +283,6 @@
 
   LayoutObject& layout_object_;
   const PhysicalSize size_;
-  scoped_refptr<NGBreakToken> break_token_;
 
   const unsigned type_ : 2;      // NGFragmentType
   const unsigned sub_type_ : 3;  // NGBoxType, NGTextType, or NGLineBoxType
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.cc
index 7dead57..fdc8bc0 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.cc
@@ -72,8 +72,8 @@
   const SVGPaint& paint =
       apply_to_fill ? svg_style.FillPaint() : svg_style.StrokePaint();
   const SVGPaint& visited_paint = apply_to_fill
-                                      ? svg_style.VisitedLinkFillPaint()
-                                      : svg_style.VisitedLinkStrokePaint();
+                                      ? svg_style.InternalVisitedFillPaint()
+                                      : svg_style.InternalVisitedStrokePaint();
 
   // If we have no, ignore it.
   if (paint.IsNone())
diff --git a/third_party/blink/renderer/core/loader/idleness_detector.cc b/third_party/blink/renderer/core/loader/idleness_detector.cc
index 56c3d7ad..bd75d24 100644
--- a/third_party/blink/renderer/core/loader/idleness_detector.cc
+++ b/third_party/blink/renderer/core/loader/idleness_detector.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/loader/idleness_detector.h"
 
 #include "base/logging.h"
+#include "base/time/default_tick_clock.h"
 #include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
 #include "third_party/blink/public/platform/platform.h"
@@ -19,6 +20,10 @@
 #include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
 
+namespace {
+const base::TickClock* g_clock = nullptr;
+}  // namespace
+
 namespace blink {
 
 constexpr TimeDelta IdlenessDetector::kNetworkQuietWindow;
@@ -93,7 +98,7 @@
   if (request_count > 2)
     return;
 
-  TimeTicks timestamp = CurrentTimeTicks();
+  TimeTicks timestamp = g_clock->NowTicks();
   // Arriving at =2 updates the quiet_2 base timestamp.
   // Arriving at <2 sets the quiet_2 base timestamp only if
   // it was not already set.
@@ -199,6 +204,8 @@
           local_frame->GetTaskRunner(TaskType::kInternalLoading),
           this,
           &IdlenessDetector::NetworkQuietTimerFired) {
+  if (!g_clock)
+    g_clock = base::DefaultTickClock::GetInstance();
   if (local_frame->GetSettings()) {
     network_quiet_window_ = TimeDelta::FromSecondsD(
         local_frame->GetSettings()->GetNetworkQuietTimeout());
@@ -221,6 +228,11 @@
   }
 }
 
+// static
+void IdlenessDetector::SetTickClockForTesting(const base::TickClock* clock) {
+  g_clock = clock;
+}
+
 void IdlenessDetector::Trace(blink::Visitor* visitor) {
   visitor->Trace(local_frame_);
 }
diff --git a/third_party/blink/renderer/core/loader/idleness_detector.h b/third_party/blink/renderer/core/loader/idleness_detector.h
index 2997d44..2288eb7a 100644
--- a/third_party/blink/renderer/core/loader/idleness_detector.h
+++ b/third_party/blink/renderer/core/loader/idleness_detector.h
@@ -11,6 +11,10 @@
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/timer.h"
 
+namespace base {
+class TickClock;
+}
+
 namespace blink {
 
 class LocalFrame;
@@ -39,6 +43,9 @@
   TimeTicks GetNetworkIdleTime();
   bool NetworkIsAlmostIdle();
 
+  // The caller owns the |clock| which must outlive the IdlenessDetector.
+  static void SetTickClockForTesting(const base::TickClock* clock);
+
   void Trace(blink::Visitor*);
 
  private:
diff --git a/third_party/blink/renderer/core/loader/idleness_detector_test.cc b/third_party/blink/renderer/core/loader/idleness_detector_test.cc
index fa7542d5..cda6f95 100644
--- a/third_party/blink/renderer/core/loader/idleness_detector_test.cc
+++ b/third_party/blink/renderer/core/loader/idleness_detector_test.cc
@@ -13,11 +13,19 @@
 class IdlenessDetectorTest : public PageTestBase {
  protected:
   void SetUp() override {
-    platform_time_ = CurrentTimeTicks();
+    auto task_runner = platform_->test_task_runner();
+    platform_time_ = task_runner->NowTicks();
     DCHECK(!platform_time_.is_null());
+    IdlenessDetector::SetTickClockForTesting(task_runner->GetMockTickClock());
     PageTestBase::SetUp();
   }
 
+  void TearDown() override {
+    PageTestBase::TearDown();
+    IdlenessDetector::SetTickClockForTesting(
+        base::DefaultTickClock::GetInstance());
+  }
+
   IdlenessDetector* Detector() { return GetFrame().GetIdlenessDetector(); }
 
   bool IsNetworkQuietTimerActive() {
diff --git a/third_party/blink/renderer/core/loader/long_task_detector_test.cc b/third_party/blink/renderer/core/loader/long_task_detector_test.cc
index 8e793b8..c40748e8 100644
--- a/third_party/blink/renderer/core/loader/long_task_detector_test.cc
+++ b/third_party/blink/renderer/core/loader/long_task_detector_test.cc
@@ -36,9 +36,9 @@
  public:
   // Public because it's executed on a task queue.
   void DummyTaskWithDuration(base::TimeDelta duration) {
-    dummy_task_start_time_ = CurrentTimeTicks();
+    dummy_task_start_time_ = platform_->test_task_runner()->NowTicks();
     platform_->AdvanceClock(duration);
-    dummy_task_end_time_ = CurrentTimeTicks();
+    dummy_task_end_time_ = platform_->test_task_runner()->NowTicks();
   }
 
  protected:
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_test.cc b/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
index decab27..f6371ce 100644
--- a/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
+++ b/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
@@ -1400,9 +1400,7 @@
 }
 
 TEST(ImageResourceTest, FetchAllowPlaceholderDataURL) {
-  KURL test_url("data:image/jpeg;base64," +
-                Base64Encode(reinterpret_cast<const char*>(kJpegImage),
-                             sizeof(kJpegImage)));
+  KURL test_url("data:image/jpeg;base64," + Base64Encode(kJpegImage));
   FetchParameters params{ResourceRequest(test_url)};
   params.SetAllowImagePlaceholder();
   ImageResource* image_resource = ImageResource::Fetch(params, CreateFetcher());
diff --git a/third_party/blink/renderer/core/mojo/mojo.cc b/third_party/blink/renderer/core/mojo/mojo.cc
index 4f0e5632..ecb71fb7 100644
--- a/third_party/blink/renderer/core/mojo/mojo.cc
+++ b/third_party/blink/renderer/core/mojo/mojo.cc
@@ -100,8 +100,7 @@
                          const String& interface_name,
                          MojoHandle* request_handle,
                          const String& scope) {
-  std::string name =
-      StringUTF8Adaptor(interface_name).AsStringPiece().as_string();
+  std::string name = interface_name.Utf8();
   auto handle =
       mojo::ScopedMessagePipeHandle::From(request_handle->TakeHandle());
 
diff --git a/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.cc b/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.cc
index 05ed60bc..d386872 100644
--- a/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.cc
+++ b/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.cc
@@ -55,8 +55,7 @@
     return;
   }
 
-  std::string interface_name =
-      StringUTF8Adaptor(interface_name_).AsStringPiece().as_string();
+  std::string interface_name = interface_name_.Utf8();
 
   if (process_scope_) {
     service_manager::Connector* connector = Platform::Current()->GetConnector();
@@ -100,8 +99,7 @@
     return;
 
   started_ = false;
-  std::string interface_name =
-      StringUTF8Adaptor(interface_name_).AsStringPiece().as_string();
+  std::string interface_name = interface_name_.Utf8();
 
   if (process_scope_) {
     auto filter = service_manager::ServiceFilter::ByName(
diff --git a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
index 6bef0e9..f4a9a8f 100644
--- a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
+++ b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h"
 
+#include "base/time/default_tick_clock.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/core/css/font_face_set_document.h"
 #include "third_party/blink/renderer/core/paint/paint_timing.h"
@@ -21,6 +22,7 @@
 // Meaningful Paint.
 const int kBlankCharactersThreshold = 200;
 
+const base::TickClock* g_clock = nullptr;
 }  // namespace
 
 FirstMeaningfulPaintDetector& FirstMeaningfulPaintDetector::From(
@@ -30,7 +32,10 @@
 
 FirstMeaningfulPaintDetector::FirstMeaningfulPaintDetector(
     PaintTiming* paint_timing)
-    : paint_timing_(paint_timing) {}
+    : paint_timing_(paint_timing) {
+  if (!g_clock)
+    g_clock = base::DefaultTickClock::GetInstance();
+}
 
 Document* FirstMeaningfulPaintDetector::GetDocument() {
   return paint_timing_->GetSupplementable();
@@ -84,7 +89,7 @@
   // Skip document background-only paints.
   if (paint_timing_->FirstPaintRendered().is_null())
     return;
-  provisional_first_meaningful_paint_ = CurrentTimeTicks();
+  provisional_first_meaningful_paint_ = g_clock->NowTicks();
   next_paint_is_meaningful_ = false;
 
   if (network2_quiet_reached_)
@@ -275,6 +280,12 @@
       swap_stamp, had_user_input_before_provisional_first_meaningful_paint_);
 }
 
+// static
+void FirstMeaningfulPaintDetector::SetTickClockForTesting(
+    const base::TickClock* clock) {
+  g_clock = clock;
+}
+
 void FirstMeaningfulPaintDetector::Trace(blink::Visitor* visitor) {
   visitor->Trace(paint_timing_);
 }
diff --git a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
index ca390f18..350ee72d 100644
--- a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
+++ b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
@@ -12,6 +12,10 @@
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
+namespace base {
+class TickClock;
+}
+
 namespace blink {
 
 class Document;
@@ -41,6 +45,9 @@
   void OnNetwork0Quiet();
   void OnNetwork2Quiet();
 
+  // The caller owns the |clock| which must outlive the paint detector.
+  static void SetTickClockForTesting(const base::TickClock* clock);
+
   void Trace(blink::Visitor*);
 
   enum HadUserInput { kNoUserInput, kHadUserInput, kHadUserInputEnumMax };
diff --git a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
index aa4923c6a..5cea8fab 100644
--- a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
+++ b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
@@ -19,12 +19,25 @@
  protected:
   void SetUp() override {
     platform_->AdvanceClock(TimeDelta::FromSeconds(1));
+    const base::TickClock* test_clock =
+        platform_->test_task_runner()->GetMockTickClock();
+    FirstMeaningfulPaintDetector::SetTickClockForTesting(test_clock);
     PageTestBase::SetUp();
+    GetPaintTiming().SetTickClockForTesting(test_clock);
   }
 
+  void TearDown() override {
+    const base::TickClock* clock = base::DefaultTickClock::GetInstance();
+    GetPaintTiming().SetTickClockForTesting(clock);
+    PageTestBase::TearDown();
+    FirstMeaningfulPaintDetector::SetTickClockForTesting(clock);
+  }
+
+  base::TimeTicks Now() { return platform_->test_task_runner()->NowTicks(); }
+
   TimeTicks AdvanceClockAndGetTime() {
     platform_->AdvanceClock(TimeDelta::FromSeconds(1));
-    return CurrentTimeTicks();
+    return Now();
   }
 
   PaintTiming& GetPaintTiming() { return PaintTiming::From(GetDocument()); }
@@ -62,21 +75,20 @@
 
   void ClearFirstPaintSwapPromise() {
     platform_->AdvanceClock(TimeDelta::FromMilliseconds(1));
-    GetPaintTiming().ReportSwapTime(PaintEvent::kFirstPaint,
-                                    WebWidgetClient::SwapResult::kDidSwap,
-                                    CurrentTimeTicks());
+    GetPaintTiming().ReportSwapTime(
+        PaintEvent::kFirstPaint, WebWidgetClient::SwapResult::kDidSwap, Now());
   }
 
   void ClearFirstContentfulPaintSwapPromise() {
     platform_->AdvanceClock(TimeDelta::FromMilliseconds(1));
     GetPaintTiming().ReportSwapTime(PaintEvent::kFirstContentfulPaint,
                                     WebWidgetClient::SwapResult::kDidSwap,
-                                    CurrentTimeTicks());
+                                    Now());
   }
 
   void ClearProvisionalFirstMeaningfulPaintSwapPromise() {
     platform_->AdvanceClock(TimeDelta::FromMilliseconds(1));
-    ClearProvisionalFirstMeaningfulPaintSwapPromise(CurrentTimeTicks());
+    ClearProvisionalFirstMeaningfulPaintSwapPromise(Now());
   }
 
   void ClearProvisionalFirstMeaningfulPaintSwapPromise(
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
index 03158ea..17f1b01ed7 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -365,7 +365,9 @@
       return fragment;
 
     scoped_refptr<NGPaintFragment>* next = &(*fragment)->next_fragmented_;
-    if ((*fragment)->PhysicalFragment().BreakToken() == break_token)
+    auto* container =
+        DynamicTo<NGPhysicalContainerFragment>((*fragment)->PhysicalFragment());
+    if (container && container->BreakToken() == break_token)
       return next;
     fragment = next;
   }
diff --git a/third_party/blink/renderer/core/paint/paint_timing.cc b/third_party/blink/renderer/core/paint/paint_timing.cc
index c235c7b..9f5a5c1 100644
--- a/third_party/blink/renderer/core/paint/paint_timing.cc
+++ b/third_party/blink/renderer/core/paint/paint_timing.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/time/default_tick_clock.h"
 #include "third_party/blink/public/platform/web_layer_tree_view.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -59,7 +60,7 @@
   // markFirstPaint().
   if (!first_paint_.is_null())
     return;
-  SetFirstPaint(CurrentTimeTicks());
+  SetFirstPaint(clock_->NowTicks());
 }
 
 void PaintTiming::MarkFirstContentfulPaint() {
@@ -69,13 +70,13 @@
   // markFirstContentfulPaint().
   if (!first_contentful_paint_.is_null())
     return;
-  SetFirstContentfulPaint(CurrentTimeTicks());
+  SetFirstContentfulPaint(clock_->NowTicks());
 }
 
 void PaintTiming::MarkFirstImagePaint() {
   if (!first_image_paint_.is_null())
     return;
-  first_image_paint_ = CurrentTimeTicks();
+  first_image_paint_ = clock_->NowTicks();
   SetFirstContentfulPaint(first_image_paint_);
   RegisterNotifySwapTime(PaintEvent::kFirstImagePaint);
 }
@@ -138,6 +139,10 @@
   fmp_detector_->NotifyPaint();
 }
 
+void PaintTiming::SetTickClockForTesting(const base::TickClock* clock) {
+  clock_ = clock;
+}
+
 void PaintTiming::Trace(blink::Visitor* visitor) {
   visitor->Trace(fmp_detector_);
   Supplement<Document>::Trace(visitor);
@@ -145,7 +150,8 @@
 
 PaintTiming::PaintTiming(Document& document)
     : Supplement<Document>(document),
-      fmp_detector_(MakeGarbageCollected<FirstMeaningfulPaintDetector>(this)) {}
+      fmp_detector_(MakeGarbageCollected<FirstMeaningfulPaintDetector>(this)),
+      clock_(base::DefaultTickClock::GetInstance()) {}
 
 LocalFrame* PaintTiming::GetFrame() const {
   return GetSupplementable()->GetFrame();
diff --git a/third_party/blink/renderer/core/paint/paint_timing.h b/third_party/blink/renderer/core/paint/paint_timing.h
index 3279e17..7dd65a90 100644
--- a/third_party/blink/renderer/core/paint/paint_timing.h
+++ b/third_party/blink/renderer/core/paint/paint_timing.h
@@ -17,6 +17,10 @@
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
+namespace base {
+class TickClock;
+}
+
 namespace blink {
 
 class LocalFrame;
@@ -103,6 +107,9 @@
 
   void ReportSwapResultHistogram(WebWidgetClient::SwapResult);
 
+  // The caller owns the |clock| which must outlive the PaintTiming.
+  void SetTickClockForTesting(const base::TickClock* clock);
+
   void Trace(blink::Visitor*) override;
 
  private:
@@ -154,6 +161,8 @@
 
   Member<FirstMeaningfulPaintDetector> fmp_detector_;
 
+  const base::TickClock* clock_;
+
   FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest, NoFirstPaint);
   FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest, OneLayout);
   FRIEND_TEST_ALL_PREFIXES(FirstMeaningfulPaintDetectorTest,
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index 4f6003f..d74c7d4 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -2015,8 +2015,8 @@
       ComputedStyleInitialValues::InitialColumnRuleColor());
   SetColumnRuleColorIsCurrentColor(
       ComputedStyleInitialValues::InitialColumnRuleColorIsCurrentColor());
-  SetVisitedLinkColumnRuleColorInternal(
-      ComputedStyleInitialValues::InitialVisitedLinkColumnRuleColor());
+  SetInternalVisitedColumnRuleColorInternal(
+      ComputedStyleInitialValues::InitialInternalVisitedColumnRuleColor());
   SetColumnCountInternal(ComputedStyleInitialValues::InitialColumnCount());
   SetHasAutoColumnCountInternal(
       ComputedStyleInitialValues::InitialHasAutoColumnCount());
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index 84acefe..11a41817 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -108,6 +108,8 @@
 class InternalVisitedBorderTopColor;
 class InternalVisitedCaretColor;
 class InternalVisitedColor;
+class InternalVisitedColumnRuleColor;
+class InternalVisitedOutlineColor;
 class InternalVisitedTextDecorationColor;
 class InternalVisitedTextEmphasisColor;
 class InternalVisitedTextFillColor;
@@ -207,6 +209,8 @@
   friend class css_longhand::InternalVisitedBorderTopColor;
   friend class css_longhand::InternalVisitedCaretColor;
   friend class css_longhand::InternalVisitedColor;
+  friend class css_longhand::InternalVisitedColumnRuleColor;
+  friend class css_longhand::InternalVisitedOutlineColor;
   friend class css_longhand::InternalVisitedTextDecorationColor;
   friend class css_longhand::InternalVisitedTextEmphasisColor;
   friend class css_longhand::InternalVisitedTextFillColor;
@@ -2382,11 +2386,11 @@
   void SetInternalVisitedBorderTopColor(const StyleColor& v) {
     SetInternalVisitedBorderTopColorInternal(v);
   }
-  void SetVisitedLinkOutlineColor(const StyleColor& v) {
-    SetVisitedLinkOutlineColorInternal(v);
+  void SetInternalVisitedOutlineColor(const StyleColor& v) {
+    SetInternalVisitedOutlineColorInternal(v);
   }
-  void SetVisitedLinkColumnRuleColor(const StyleColor& v) {
-    SetVisitedLinkColumnRuleColorInternal(v);
+  void SetInternalVisitedColumnRuleColor(const StyleColor& v) {
+    SetInternalVisitedColumnRuleColorInternal(v);
   }
   void SetInternalVisitedTextDecorationColor(const StyleColor& v) {
     SetInternalVisitedTextDecorationColorInternal(v);
@@ -2560,15 +2564,17 @@
                 other.InternalVisitedBorderTopColor() ||
             !BorderTopWidth());
   }
-  StyleColor VisitedLinkOutlineColor() const {
-    return VisitedLinkOutlineColorInternal();
+  StyleColor InternalVisitedOutlineColor() const {
+    return InternalVisitedOutlineColorInternal();
   }
-  bool VisitedLinkOutlineColorHasNotChanged(const ComputedStyle& other) const {
-    return (VisitedLinkOutlineColor() == other.VisitedLinkOutlineColor() ||
+  bool InternalVisitedOutlineColorHasNotChanged(
+      const ComputedStyle& other) const {
+    return (InternalVisitedOutlineColor() ==
+                other.InternalVisitedOutlineColor() ||
             !OutlineWidth());
   }
-  StyleColor VisitedLinkColumnRuleColor() const {
-    return VisitedLinkColumnRuleColorInternal();
+  StyleColor InternalVisitedColumnRuleColor() const {
+    return InternalVisitedColumnRuleColorInternal();
   }
   StyleColor InternalVisitedTextDecorationColor() const {
     return InternalVisitedTextDecorationColorInternal();
diff --git a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5 b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
index d606ca1..42896ae 100644
--- a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
+++ b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
@@ -110,7 +110,7 @@
                 "-webkit-box-pack", "-webkit-box-orient",
                 "grid-row-start", "grid-row-end", "grid-column-start", "grid-column-end",
                 "column-gap", "column-width", "column-rule-style",
-                "column-rule-width", "column-rule-color", "ColumnRuleColorIsCurrentColor", "VisitedLinkColumnRuleColor",
+                "column-rule-width", "column-rule-color", "ColumnRuleColorIsCurrentColor", "-internal-visited-column-rule-color",
                 "column-count", "HasAutoColumnCount", "HasAutoColumnWidth", "column-fill", "column-span",],
         methods_to_diff: [
           {
@@ -304,8 +304,8 @@
             field_dependencies: ["-internal-visited-border-top-color"]
           },
           {
-            predicate: "a.VisitedLinkOutlineColorHasNotChanged(b)",
-            field_dependencies: ["VisitedLinkOutlineColor"]
+            predicate: "a.InternalVisitedOutlineColorHasNotChanged(b)",
+            field_dependencies: ["-internal-visited-outline-color"]
           },
         ]
     },
diff --git a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
index 3223d713..09fcdce 100644
--- a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
+++ b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
@@ -610,14 +610,6 @@
       field_group: "*",
     },
     {
-      name: "VisitedLinkOutlineColor",
-      field_template: "external",
-      type_name: "StyleColor",
-      field_group: "*",
-      default_value: "StyleColor::CurrentColor()",
-      computed_style_custom_functions: ["getter", "setter"],
-    },
-    {
       name: "CallbackSelectors",
       field_template: "external",
       type_name: "Vector<String>",
@@ -792,15 +784,6 @@
       field_group: "*->multi-col",
     },
     {
-      name: "VisitedLinkColumnRuleColor",
-      field_template: "external",
-      type_name: "StyleColor",
-      field_group: "*->multi-col",
-      default_value: "StyleColor::CurrentColor()",
-      include_paths: ["third_party/blink/renderer/core/css/style_color.h"],
-      computed_style_custom_functions: ["getter", "setter"],
-    },
-    {
       name: "HasAutoColumnWidth",
       field_template: "primitive",
       type_name: "bool",
diff --git a/third_party/blink/renderer/core/style/svg_computed_style.h b/third_party/blink/renderer/core/style/svg_computed_style.h
index 443dd625..8c1d1eb 100644
--- a/third_party/blink/renderer/core/style/svg_computed_style.h
+++ b/third_party/blink/renderer/core/style/svg_computed_style.h
@@ -190,7 +190,7 @@
       fill.Access()->paint = paint;
   }
 
-  void SetVisitedLinkFillPaint(const SVGPaint& paint) {
+  void SetInternalVisitedFillPaint(const SVGPaint& paint) {
     if (!(fill->visited_link_paint == paint))
       fill.Access()->visited_link_paint = paint;
   }
@@ -205,7 +205,7 @@
       stroke.Access()->paint = paint;
   }
 
-  void SetVisitedLinkStrokePaint(const SVGPaint& paint) {
+  void SetInternalVisitedStrokePaint(const SVGPaint& paint) {
     if (!(stroke->visited_link_paint == paint))
       stroke.Access()->visited_link_paint = paint;
   }
@@ -363,21 +363,21 @@
   }
   EPaintOrderType PaintOrderType(unsigned index) const;
 
-  const SVGPaint& VisitedLinkFillPaint() const {
+  const SVGPaint& InternalVisitedFillPaint() const {
     return fill->visited_link_paint;
   }
-  const SVGPaint& VisitedLinkStrokePaint() const {
+  const SVGPaint& InternalVisitedStrokePaint() const {
     return stroke->visited_link_paint;
   }
 
   bool IsFillColorCurrentColor() const {
     return FillPaint().HasCurrentColor() ||
-           VisitedLinkFillPaint().HasCurrentColor();
+           InternalVisitedFillPaint().HasCurrentColor();
   }
 
   bool IsStrokeColorCurrentColor() const {
     return StrokePaint().HasCurrentColor() ||
-           VisitedLinkStrokePaint().HasCurrentColor();
+           InternalVisitedStrokePaint().HasCurrentColor();
   }
 
   // convenience
diff --git a/third_party/blink/renderer/core/style/svg_computed_style_test.cc b/third_party/blink/renderer/core/style/svg_computed_style_test.cc
index e7ec9a4..2559a45 100644
--- a/third_party/blink/renderer/core/style/svg_computed_style_test.cc
+++ b/third_party/blink/renderer/core/style/svg_computed_style_test.cc
@@ -45,8 +45,8 @@
   {
     scoped_refptr<SVGComputedStyle> svg1 = SVGComputedStyle::Create();
     scoped_refptr<SVGComputedStyle> svg2 = SVGComputedStyle::Create();
-    svg1->SetVisitedLinkStrokePaint(SVGComputedStyle::InitialStrokePaint());
-    svg2->SetVisitedLinkStrokePaint(SVGComputedStyle::InitialStrokePaint());
+    svg1->SetInternalVisitedStrokePaint(SVGComputedStyle::InitialStrokePaint());
+    svg2->SetInternalVisitedStrokePaint(SVGComputedStyle::InitialStrokePaint());
     EXPECT_FALSE(svg1->Diff(*svg2).HasDifference());
   }
 }
diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
index 560f790..384330e4 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
+++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
@@ -265,7 +265,7 @@
     case CredentialManagerError::PROTECTION_POLICY_INCONSISTENT:
       return MakeGarbageCollected<DOMException>(
           DOMExceptionCode::kNotSupportedError,
-          "Requested protection policy is inconsistent or incongurent with "
+          "Requested protection policy is inconsistent or incongruent with "
           "other requested parameters.");
     case CredentialManagerError::ANDROID_ALGORITHM_UNSUPPORTED:
       return MakeGarbageCollected<DOMException>(
diff --git a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc
index 8905293..9aff2b7 100644
--- a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc
@@ -32,7 +32,8 @@
 void PaintRenderingContext2D::InitializePaintRecorder() {
   paint_recorder_ = std::make_unique<PaintRecorder>();
   cc::PaintCanvas* canvas = paint_recorder_->beginRecording(
-      container_size_.Width(), container_size_.Height());
+      container_size_.Width() / effective_zoom_,
+      container_size_.Height() / effective_zoom_);
 
   // Always save an initial frame, to support resetting the top level matrix
   // and clip.
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.cc b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
index a01b179a..5977ddd 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_parser.cc
+++ b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
@@ -25,8 +25,7 @@
 bool IsValidMimeType(const String& mime_type) {
   if (mime_type.StartsWith('.'))
     return true;
-  return net::ParseMimeTypeWithoutParameter(
-      StringUTF8Adaptor(mime_type).AsStdString(), nullptr, nullptr);
+  return net::ParseMimeTypeWithoutParameter(mime_type.Utf8(), nullptr, nullptr);
 }
 
 bool VerifyFiles(const Vector<mojom::blink::ManifestFileFilterPtr>& files) {
@@ -246,8 +245,7 @@
   if (!display.has_value())
     return kWebDisplayModeUndefined;
 
-  WebDisplayMode display_enum =
-      WebDisplayModeFromString(StringUTF8Adaptor(*display).AsStdString());
+  WebDisplayMode display_enum = WebDisplayModeFromString(display->Utf8());
   if (display_enum == kWebDisplayModeUndefined)
     AddErrorInfo("unknown 'display' value ignored.");
   return display_enum;
@@ -261,8 +259,7 @@
     return kWebScreenOrientationLockDefault;
 
   WebScreenOrientationLockType orientation_enum =
-      WebScreenOrientationLockTypeFromString(
-          StringUTF8Adaptor(*orientation).AsStdString());
+      WebScreenOrientationLockTypeFromString(orientation->Utf8());
   if (orientation_enum == kWebScreenOrientationLockDefault)
     AddErrorInfo("unknown 'orientation' value ignored.");
   return orientation_enum;
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_list_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_list_element.cc
index c10ade7..63816e6f 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_list_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_list_element.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_list_element.h"
 
+#include "base/time/default_tick_clock.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_token_list.h"
@@ -18,7 +19,8 @@
 
 MediaControlOverflowMenuListElement::MediaControlOverflowMenuListElement(
     MediaControlsImpl& media_controls)
-    : MediaControlPopupMenuElement(media_controls) {
+    : MediaControlPopupMenuElement(media_controls),
+      clock_(base::DefaultTickClock::GetInstance()) {
   SetShadowPseudoId(
       AtomicString("-internal-media-controls-overflow-menu-list"));
   setAttribute(html_names::kRoleAttr, "menu");
@@ -45,7 +47,7 @@
                                 : "Media.Controls.Overflow.TimeToDismiss",
                             1, 100, 100);
   histogram.Count(static_cast<int32_t>(
-      (CurrentTimeTicks() - time_shown_.value()).InSeconds()));
+      (clock_->NowTicks() - time_shown_.value()).InSeconds()));
 
   time_shown_.reset();
 }
@@ -68,7 +70,7 @@
   // Record the time the overflow menu was shown to a histogram.
   if (wanted) {
     DCHECK(!time_shown_);
-    time_shown_ = CurrentTimeTicks();
+    time_shown_ = clock_->NowTicks();
   } else if (time_shown_) {
     // Records the time taken to dismiss using a task runner. This ensures the
     // time to dismiss is always called after the time to action (if there is
@@ -88,4 +90,9 @@
   MediaControlPopupMenuElement::OnItemSelected();
 }
 
+void MediaControlOverflowMenuListElement::SetTickClockForTesting(
+    const base::TickClock* clock) {
+  clock_ = clock;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_list_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_list_element.h
index 00d5d89..74e0584 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_list_element.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_list_element.h
@@ -10,6 +10,10 @@
 #include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
+namespace base {
+class TickClock;
+}
+
 namespace blink {
 
 class Event;
@@ -28,6 +32,9 @@
   void SetIsWanted(bool) final;
   void OnItemSelected() final;
 
+  // The caller owns the |clock| which must outlive the media control element.
+  MODULES_EXPORT void SetTickClockForTesting(const base::TickClock* clock);
+
  private:
   enum TimeTakenHistogram {
     kTimeToAction,
@@ -40,6 +47,7 @@
   TaskHandle current_task_handle_;
 
   base::Optional<WTF::TimeTicks> time_shown_;
+  const base::TickClock* clock_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
index 0339be8..4b09d747 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
@@ -244,6 +244,9 @@
   MediaControlOverflowMenuButtonElement* OverflowMenuButtonElement() const {
     return media_controls_->overflow_menu_;
   }
+  MediaControlOverflowMenuListElement* OverflowMenuListElement() const {
+    return media_controls_->overflow_list_;
+  }
 
   MockWebMediaPlayerForImpl* WebMediaPlayer() {
     return static_cast<MockWebMediaPlayerForImpl*>(
@@ -1188,6 +1191,9 @@
 
 TEST_F(MediaControlsImplTestWithMockScheduler,
        OverflowMenuMetricsTimeToAction) {
+  OverflowMenuListElement()->SetTickClockForTesting(
+      platform()->test_task_runner()->GetMockTickClock());
+
   GetHistogramTester().ExpectTotalCount(kTimeToActionHistogramName, 0);
   GetHistogramTester().ExpectTotalCount(kTimeToDismissHistogramName, 0);
 
@@ -1224,6 +1230,9 @@
 
 TEST_F(MediaControlsImplTestWithMockScheduler,
        OverflowMenuMetricsTimeToDismiss) {
+  OverflowMenuListElement()->SetTickClockForTesting(
+      platform()->test_task_runner()->GetMockTickClock());
+
   GetHistogramTester().ExpectTotalCount(kTimeToDismissHistogramName, 0);
   GetHistogramTester().ExpectTotalCount(kTimeToActionHistogramName, 0);
 
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc
index daec604..0b8179a 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc
@@ -480,10 +480,9 @@
 void CanvasCaptureHandler::AddVideoCapturerSourceToVideoTrack(
     std::unique_ptr<media::VideoCapturerSource> source,
     blink::WebMediaStreamTrack* web_track) {
-  Vector<char> base64_track_id;
-  Base64Encode(base::RandBytesAsString(64).c_str(), base64_track_id);
-  const auto track_id =
-      WebString::FromUTF8(base64_track_id.data(), base64_track_id.size());
+  uint8_t track_id_bytes[64];
+  base::RandBytes(track_id_bytes, sizeof(track_id_bytes));
+  WebString track_id = Base64Encode(track_id_bytes);
   media::VideoCaptureFormats preferred_formats = source->GetPreferredFormats();
   blink::MediaStreamVideoSource* media_stream_source =
       new blink::MediaStreamVideoCapturerSource(
diff --git a/third_party/blink/renderer/modules/mediastream/BUILD.gn b/third_party/blink/renderer/modules/mediastream/BUILD.gn
index 018f6f0..4796be7 100644
--- a/third_party/blink/renderer/modules/mediastream/BUILD.gn
+++ b/third_party/blink/renderer/modules/mediastream/BUILD.gn
@@ -71,5 +71,6 @@
     "//skia",
     "//testing/gmock",
     "//third_party/blink/public/mojom:mojom_platform_blink_headers",
+    "//third_party/webrtc_overrides:init_webrtc",
   ]
 }
diff --git a/third_party/blink/renderer/modules/notifications/notification_image_loader.cc b/third_party/blink/renderer/modules/notifications/notification_image_loader.cc
index da43cc2..6ef821ec 100644
--- a/third_party/blink/renderer/modules/notifications/notification_image_loader.cc
+++ b/third_party/blink/renderer/modules/notifications/notification_image_loader.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include "base/numerics/safe_conversions.h"
+#include "base/time/default_tick_clock.h"
 #include "skia/ext/image_operations.h"
 #include "third_party/blink/public/platform/modules/notifications/web_notification_constants.h"
 #include "third_party/blink/public/platform/web_url_request.h"
@@ -48,8 +49,9 @@
 
 namespace blink {
 
-NotificationImageLoader::NotificationImageLoader(Type type)
-    : type_(type), stopped_(false) {}
+NotificationImageLoader::NotificationImageLoader(Type type,
+                                                 const base::TickClock* clock)
+    : type_(type), stopped_(false), clock_(clock) {}
 
 NotificationImageLoader::~NotificationImageLoader() = default;
 
@@ -58,7 +60,7 @@
                                     ImageCallback image_callback) {
   DCHECK(!stopped_);
 
-  start_time_ = CurrentTimeTicks();
+  start_time_ = clock_->NowTicks();
   image_callback_ = std::move(image_callback);
 
   // TODO(mvanouwerkerk): Add an entry for notifications to
@@ -105,7 +107,7 @@
   NOTIFICATION_HISTOGRAM_COUNTS(
       LoadFinishTime, type_,
       base::saturated_cast<base::HistogramBase::Sample>(
-          (CurrentTimeTicks() - start_time_).InMilliseconds()),
+          (clock_->NowTicks() - start_time_).InMilliseconds()),
       1000 * 60 * 60 /* 1 hour max */);
 
   if (data_) {
@@ -135,7 +137,7 @@
   NOTIFICATION_HISTOGRAM_COUNTS(
       LoadFailTime, type_,
       base::saturated_cast<base::HistogramBase::Sample>(
-          (CurrentTimeTicks() - start_time_).InMilliseconds()),
+          (clock_->NowTicks() - start_time_).InMilliseconds()),
       1000 * 60 * 60 /* 1 hour max */);
 
   RunCallbackWithEmptyBitmap();
diff --git a/third_party/blink/renderer/modules/notifications/notification_image_loader.h b/third_party/blink/renderer/modules/notifications/notification_image_loader.h
index f59ef9a..c975f2b 100644
--- a/third_party/blink/renderer/modules/notifications/notification_image_loader.h
+++ b/third_party/blink/renderer/modules/notifications/notification_image_loader.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include "base/memory/scoped_refptr.h"
+#include "base/time/default_tick_clock.h"
 #include "third_party/blink/renderer/core/loader/threadable_loader.h"
 #include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
@@ -37,7 +38,9 @@
   // be decoded.
   using ImageCallback = base::OnceCallback<void(const SkBitmap&)>;
 
-  explicit NotificationImageLoader(Type type);
+  NotificationImageLoader(
+      Type type,
+      const base::TickClock* clock = base::DefaultTickClock::GetInstance());
   ~NotificationImageLoader() override;
 
   // Asynchronously downloads an image from the given url, decodes the loaded
@@ -75,6 +78,7 @@
   scoped_refptr<SharedBuffer> data_;
   ImageCallback image_callback_;
   Member<ThreadableLoader> threadable_loader_;
+  const base::TickClock* clock_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/notifications/notification_image_loader_test.cc b/third_party/blink/renderer/modules/notifications/notification_image_loader_test.cc
index 7e5d5d4..6b2fe636 100644
--- a/third_party/blink/renderer/modules/notifications/notification_image_loader_test.cc
+++ b/third_party/blink/renderer/modules/notifications/notification_image_loader_test.cc
@@ -34,12 +34,12 @@
 
 class NotificationImageLoaderTest : public PageTestBase {
  public:
-  NotificationImageLoaderTest()
-      :  // Use an arbitrary type, since it only affects which UMA bucket we
-         // use.
-        loader_(MakeGarbageCollected<NotificationImageLoader>(
-            NotificationImageLoader::Type::kIcon)) {
+  NotificationImageLoaderTest() {
     EnablePlatform();
+    // Use an arbitrary type, since it only affects which UMA bucket we use.
+    loader_ = MakeGarbageCollected<NotificationImageLoader>(
+        NotificationImageLoader::Type::kIcon,
+        platform()->test_task_runner()->GetMockTickClock());
   }
 
   ~NotificationImageLoaderTest() override {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
index 7fd4971b..86288e4e 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
@@ -509,10 +509,11 @@
   if (state_ == webrtc::IceTransportState::kFailed) {
     selected_candidate_pair_ = nullptr;
   }
-  DispatchEvent(*Event::Create(event_type_names::kStatechange));
+  // Make sure the peerconnection's state is updated before the event fires.
   if (peer_connection_) {
     peer_connection_->UpdateIceConnectionState();
   }
+  DispatchEvent(*Event::Create(event_type_names::kStatechange));
   if (state_ == webrtc::IceTransportState::kClosed ||
       state_ == webrtc::IceTransportState::kFailed) {
     stop();
diff --git a/third_party/blink/renderer/modules/push_messaging/push_manager_test.cc b/third_party/blink/renderer/modules/push_messaging/push_manager_test.cc
index dbad302a..54d6be8a 100644
--- a/third_party/blink/renderer/modules/push_messaging/push_manager_test.cc
+++ b/third_party/blink/renderer/modules/push_messaging/push_manager_test.cc
@@ -106,9 +106,8 @@
   PushSubscriptionOptionsInit* options =
       MakeGarbageCollected<PushSubscriptionOptionsInit>();
   options->setApplicationServerKey(
-      ArrayBufferOrArrayBufferViewOrString::FromString(WTF::Base64Encode(
-          reinterpret_cast<const char*>(kApplicationServerKey),
-          kApplicationServerKeyLength)));
+      ArrayBufferOrArrayBufferViewOrString::FromString(
+          Base64Encode(kApplicationServerKey)));
 
   DummyExceptionStateForTesting exception_state;
   PushSubscriptionOptions* output =
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc b/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc
index 0237f78..a017fa4 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc
@@ -25,6 +25,7 @@
 #include "third_party/blink/renderer/modules/webaudio/audio_worklet_thread.h"
 #include "third_party/blink/renderer/platform/testing/histogram_tester.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 
 namespace blink {
 
@@ -93,15 +94,12 @@
 
   void SetUp() override {
     helper_.Initialize();
-    frame_test_helpers::LoadFrame(helper_.LocalMainFrame(),
-                                  "data:text/html,<iframe></iframe>");
-
-    GetDocument().UpdateSecurityOrigin(
-        SecurityOrigin::Create("https", "example.com", 80));
-
-    ChildDocument().UpdateSecurityOrigin(
-        SecurityOrigin::Create("https", "cross-origin.com", 80));
-
+    frame_test_helpers::LoadHTMLString(helper_.LocalMainFrame(),
+                                       "<iframe></iframe>",
+                                       WebURL(KURL("https://example.com")));
+    frame_test_helpers::LoadHTMLString(
+        To<WebLocalFrameImpl>(helper_.LocalMainFrame()->FirstChild()), "",
+        WebURL(KURL("https://cross-origin.com")));
     GetDocument().GetSettings()->SetAutoplayPolicy(GetParam());
     ChildDocument().GetSettings()->SetAutoplayPolicy(GetParam());
 
diff --git a/third_party/blink/renderer/platform/exported/web_string.cc b/third_party/blink/renderer/platform/exported/web_string.cc
index 1ec1fbc..fbe4828 100644
--- a/third_party/blink/renderer/platform/exported/web_string.cc
+++ b/third_party/blink/renderer/platform/exported/web_string.cc
@@ -79,9 +79,7 @@
 }
 
 std::string WebString::Utf8(UTF8ConversionMode mode) const {
-  StringUTF8Adaptor utf8(impl_.get(),
-                         static_cast<WTF::UTF8ConversionMode>(mode));
-  return utf8.AsStdString();
+  return String(impl_).Utf8(static_cast<WTF::UTF8ConversionMode>(mode));
 }
 
 WebString WebString::FromUTF8(const char* data, size_t length) {
diff --git a/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc b/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc
index 1f426a0..81c234a1 100644
--- a/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc
+++ b/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc
@@ -4,17 +4,75 @@
 
 #include "third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h"
 #include "mojo/public/mojom/base/shared_memory.mojom-blink.h"
-#include "third_party/blink/public/mojom/font_unique_name_lookup/font_unique_name_lookup.mojom-blink.h"
 #include "third_party/blink/public/platform/interface_provider.h"
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
 FontUniqueNameLookupAndroid::~FontUniqueNameLookupAndroid() = default;
 
+void FontUniqueNameLookupAndroid::PrepareFontUniqueNameLookup(
+    NotifyFontUniqueNameLookupReady callback) {
+  DCHECK(!font_table_matcher_.get());
+  DCHECK(RuntimeEnabledFeatures::FontSrcLocalMatchingEnabled());
+
+  pending_callbacks_.push_back(std::move(callback));
+
+  // We bind the service on the first call to PrepareFontUniqueNameLookup. After
+  // that we do not need to make additional IPC requests to retrieve the table.
+  // The observing callback was added to the list, so all clients will be
+  // informed when the lookup table has arrived.
+  if (pending_callbacks_.size() > 1)
+    return;
+
+  EnsureServiceConnected();
+
+  service_->GetUniqueNameLookupTable(base::BindOnce(
+      &FontUniqueNameLookupAndroid::ReceiveReadOnlySharedMemoryRegion,
+      base::Unretained(this)));
+}
+
+bool FontUniqueNameLookupAndroid::IsFontUniqueNameLookupReadyForSyncLookup() {
+  if (!RuntimeEnabledFeatures::FontSrcLocalMatchingEnabled())
+    return true;
+
+  EnsureServiceConnected();
+
+  // If we have the table already, we're ready for sync lookups.
+  if (font_table_matcher_.get())
+    return true;
+
+  // We have previously determined via IPC whether the table is sync available.
+  // Return what we found out before.
+  if (sync_available_.has_value())
+    return sync_available_.value();
+
+  // If we haven't asked the browser before, probe synchronously - if the table
+  // is available on the browser side, we can continue with sync operation.
+
+  bool sync_available_from_mojo = false;
+  base::ReadOnlySharedMemoryRegion shared_memory_region;
+  service_->GetUniqueNameLookupTableIfAvailable(&sync_available_from_mojo,
+                                                &shared_memory_region);
+  sync_available_ = sync_available_from_mojo;
+
+  if (*sync_available_) {
+    // Adopt the shared memory region, do not notify anyone in callbacks as
+    // PrepareFontUniqueNameLookup must not have been called yet. Just return
+    // true from this function.
+    DCHECK_EQ(pending_callbacks_.size(), 0u);
+    ReceiveReadOnlySharedMemoryRegion(std::move(shared_memory_region));
+  }
+
+  // If it wasn't available synchronously LocalFontFaceSource has to call
+  // PrepareFontUniqueNameLookup.
+  return *sync_available_;
+}
+
 sk_sp<SkTypeface> FontUniqueNameLookupAndroid::MatchUniqueName(
     const String& font_unique_name) {
-  if (!EnsureMatchingServiceConnected())
+  if (!IsFontUniqueNameLookupReadyForSyncLookup())
     return nullptr;
   base::Optional<FontTableMatcher::MatchResult> match_result =
       font_table_matcher_->MatchName(font_unique_name.Utf8().c_str());
@@ -24,26 +82,22 @@
                                   match_result->ttc_index);
 }
 
-bool FontUniqueNameLookupAndroid::EnsureMatchingServiceConnected() {
-  if (font_table_matcher_)
-    return true;
+void FontUniqueNameLookupAndroid::EnsureServiceConnected() {
+  if (service_)
+    return;
 
-  mojom::blink::FontUniqueNameLookupPtr service;
   Platform::Current()->GetInterfaceProvider()->GetInterface(
-      mojo::MakeRequest(&service));
+      mojo::MakeRequest(&service_));
+}
 
-  base::ReadOnlySharedMemoryRegion region_ptr;
-  if (!service->GetUniqueNameLookupTable(&region_ptr)) {
-    // Tests like StyleEngineTest do not set up a full browser where Blink can
-    // connect to a browser side service for font lookups. Placing a DCHECK here
-    // is too strict for such a case.
-    LOG(ERROR) << "Unable to connect to browser side service for src: local() "
-                  "font lookup.";
-    return false;
+void FontUniqueNameLookupAndroid::ReceiveReadOnlySharedMemoryRegion(
+    base::ReadOnlySharedMemoryRegion shared_memory_region) {
+  font_table_matcher_ =
+      std::make_unique<FontTableMatcher>(shared_memory_region.Map());
+  while (!pending_callbacks_.IsEmpty()) {
+    NotifyFontUniqueNameLookupReady callback = pending_callbacks_.TakeFirst();
+    std::move(callback).Run();
   }
-
-  font_table_matcher_ = std::make_unique<FontTableMatcher>(region_ptr.Map());
-  return true;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h b/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h
index 738fb2d..fb4a35a 100644
--- a/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h
+++ b/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h
@@ -6,7 +6,9 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_ANDROID_FONT_UNIQUE_NAME_LOOKUP_ANDROID_H_
 
 #include "third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h"
+#include "third_party/blink/public/mojom/font_unique_name_lookup/font_unique_name_lookup.mojom-blink.h"
 #include "third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
 
 #include <memory>
 
@@ -16,10 +18,23 @@
  public:
   FontUniqueNameLookupAndroid() = default;
   ~FontUniqueNameLookupAndroid() override;
+
+  bool IsFontUniqueNameLookupReadyForSyncLookup() override;
+
+  void PrepareFontUniqueNameLookup(
+      NotifyFontUniqueNameLookupReady callback) override;
+
   sk_sp<SkTypeface> MatchUniqueName(const String& font_unique_name) override;
 
  private:
-  bool EnsureMatchingServiceConnected();
+  void EnsureServiceConnected();
+
+  void ReceiveReadOnlySharedMemoryRegion(
+      base::ReadOnlySharedMemoryRegion shared_memory_region);
+
+  mojom::blink::FontUniqueNameLookupPtr service_;
+  WTF::Deque<NotifyFontUniqueNameLookupReady> pending_callbacks_;
+  base::Optional<bool> sync_available_;
 
   DISALLOW_COPY_AND_ASSIGN(FontUniqueNameLookupAndroid);
 };
diff --git a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
index 40fee4c0..d7fb1cd 100644
--- a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
+++ b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
@@ -70,7 +70,7 @@
         context_provider_wrapper)
     : paint_image_content_id_(cc::PaintImage::GetNextContentId()) {
   CHECK(image && image->isTextureBacked());
-  texture_holder_ = std::make_unique<SkiaTextureHolder>(
+  skia_texture_holder_ = std::make_unique<SkiaTextureHolder>(
       std::move(image), std::move(context_provider_wrapper));
 }
 
@@ -83,7 +83,7 @@
     IntSize mailbox_size,
     bool is_origin_top_left)
     : paint_image_content_id_(cc::PaintImage::GetNextContentId()) {
-  texture_holder_ = std::make_unique<MailboxTextureHolder>(
+  mailbox_texture_holder_ = std::make_unique<MailboxTextureHolder>(
       mailbox, sync_token, texture_id, std::move(context_provider_wrapper),
       mailbox_size, is_origin_top_left);
 }
@@ -100,7 +100,7 @@
     std::unique_ptr<viz::SingleReleaseCallback> release_callback)
     : paint_image_content_id_(cc::PaintImage::GetNextContentId()),
       release_callback_(std::move(release_callback)) {
-  texture_holder_ = std::make_unique<MailboxTextureHolder>(
+  mailbox_texture_holder_ = std::make_unique<MailboxTextureHolder>(
       mailbox, sync_token, std::move(context_provider_wrapper),
       context_thread_id, sk_image_info, texture_target, is_origin_top_left);
 }
@@ -133,8 +133,8 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   if (release_callback_) {
-    release_callback_->Run(texture_holder_->GetSyncToken(),
-                           false /* is_lost */);
+    DCHECK(mailbox_texture_holder_);
+    release_callback_->Run(GetSyncToken(), false /* is_lost */);
   }
 
   // If the original SkImage was retained, it must be destroyed on the thread
@@ -142,7 +142,7 @@
   // the regular destruction flow is fine.
   if (original_skia_image_) {
     std::unique_ptr<gpu::SyncToken> sync_token =
-        base::WrapUnique(new gpu::SyncToken(texture_holder_->GetSyncToken()));
+        base::WrapUnique(new gpu::SyncToken(GetSyncToken()));
     if (!original_skia_image_task_runner_->BelongsToCurrentThread()) {
       PostCrossThreadTask(
           *original_skia_image_task_runner_, FROM_HERE,
@@ -162,8 +162,8 @@
 void AcceleratedStaticBitmapImage::RetainOriginalSkImage() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  DCHECK(texture_holder_->IsSkiaTextureHolder());
-  original_skia_image_ = texture_holder_->GetSkImage();
+  DCHECK(skia_texture_holder_);
+  original_skia_image_ = skia_texture_holder_->GetSkImage();
   original_skia_image_context_provider_wrapper_ = ContextProviderWrapper();
   DCHECK(original_skia_image_);
 
@@ -171,18 +171,14 @@
 }
 
 IntSize AcceleratedStaticBitmapImage::Size() const {
-  return texture_holder_->Size();
+  return texture_holder()->Size();
 }
 
 scoped_refptr<StaticBitmapImage>
 AcceleratedStaticBitmapImage::MakeUnaccelerated() {
   CreateImageFromMailboxIfNeeded();
   return StaticBitmapImage::Create(
-      texture_holder_->GetSkImage()->makeNonTextureImage());
-}
-
-void AcceleratedStaticBitmapImage::UpdateSyncToken(gpu::SyncToken sync_token) {
-  texture_holder_->UpdateSyncToken(sync_token);
+      skia_texture_holder_->GetSkImage()->makeNonTextureImage());
 }
 
 bool AcceleratedStaticBitmapImage::CopyToTexture(
@@ -197,30 +193,30 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (!IsValid())
     return false;
-  // This method should only be used for cross-context copying, otherwise it's
-  // wasting overhead.
-  DCHECK(texture_holder_->IsCrossThread() ||
-         dest_gl != ContextProviderWrapper()->ContextProvider()->ContextGL());
 
   // TODO(junov) : could reduce overhead by using kOrderingBarrier when we know
   // that the source and destination context or on the same stream.
   EnsureMailbox(kUnverifiedSyncToken, GL_NEAREST);
 
-  DCHECK(texture_holder_->IsMailboxTextureHolder());
-  bool is_shared_image = texture_holder_->GetMailbox().IsSharedImage();
+  // This method should only be used for cross-context copying, otherwise it's
+  // wasting overhead.
+  DCHECK(mailbox_texture_holder_->IsCrossThread() ||
+         dest_gl != ContextProviderWrapper()->ContextProvider()->ContextGL());
+
+  bool is_shared_image = mailbox_texture_holder_->GetMailbox().IsSharedImage();
 
   // Get a texture id that |destProvider| knows about and copy from it.
   dest_gl->WaitSyncTokenCHROMIUM(
-      texture_holder_->GetSyncToken().GetConstData());
+      mailbox_texture_holder_->GetSyncToken().GetConstData());
   GLuint source_texture_id;
   if (is_shared_image) {
     source_texture_id = dest_gl->CreateAndTexStorage2DSharedImageCHROMIUM(
-        texture_holder_->GetMailbox().name);
+        mailbox_texture_holder_->GetMailbox().name);
     dest_gl->BeginSharedImageAccessDirectCHROMIUM(
         source_texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
   } else {
     source_texture_id = dest_gl->CreateAndConsumeTextureCHROMIUM(
-        texture_holder_->GetMailbox().name);
+        mailbox_texture_holder_->GetMailbox().name);
   }
   dest_gl->CopySubTextureCHROMIUM(
       source_texture_id, 0, dest_target, dest_texture_id, dest_level,
@@ -240,7 +236,7 @@
   // the above texture copy has completed.
   gpu::SyncToken sync_token;
   dest_gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
-  texture_holder_->UpdateSyncToken(sync_token);
+  mailbox_texture_holder_->UpdateSyncToken(sync_token);
 
   return true;
 }
@@ -261,7 +257,7 @@
     image = original_skia_image_;
   } else {
     CreateImageFromMailboxIfNeeded();
-    image = texture_holder_->GetSkImage();
+    image = skia_texture_holder_->GetSkImage();
   }
 
   return CreatePaintImageBuilder()
@@ -292,36 +288,36 @@
 }
 
 bool AcceleratedStaticBitmapImage::IsValid() const {
-  return texture_holder_ && texture_holder_->IsValid();
+  return texture_holder()->IsValid();
 }
 
 WebGraphicsContext3DProvider* AcceleratedStaticBitmapImage::ContextProvider()
     const {
-  if (!IsValid())
-    return nullptr;
-  return texture_holder_->ContextProvider();
+  return texture_holder()->ContextProvider();
 }
 
 base::WeakPtr<WebGraphicsContext3DProviderWrapper>
 AcceleratedStaticBitmapImage::ContextProviderWrapper() const {
   if (!IsValid())
     return nullptr;
-  return texture_holder_->ContextProviderWrapper();
+
+  return texture_holder()->ContextProviderWrapper();
 }
 
 void AcceleratedStaticBitmapImage::CreateImageFromMailboxIfNeeded() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (texture_holder_->IsSkiaTextureHolder())
+  if (skia_texture_holder_)
     return;
 
-  texture_holder_ =
-      std::make_unique<SkiaTextureHolder>(std::move(texture_holder_));
+  DCHECK(mailbox_texture_holder_);
+  skia_texture_holder_ =
+      std::make_unique<SkiaTextureHolder>(mailbox_texture_holder_.get());
 }
 
 void AcceleratedStaticBitmapImage::EnsureMailbox(MailboxSyncMode mode,
                                                  GLenum filter) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (!texture_holder_->IsMailboxTextureHolder()) {
+  if (!mailbox_texture_holder_) {
     TRACE_EVENT0("blink", "AcceleratedStaticBitmapImage::EnsureMailbox");
 
     if (!original_skia_image_) {
@@ -331,20 +327,25 @@
       RetainOriginalSkImage();
     }
 
-    texture_holder_ = std::make_unique<MailboxTextureHolder>(
-        std::move(texture_holder_), filter);
+    mailbox_texture_holder_ = std::make_unique<MailboxTextureHolder>(
+        skia_texture_holder_.get(), filter);
   }
-  texture_holder_->Sync(mode);
+  mailbox_texture_holder_->Sync(mode);
 }
 
 void AcceleratedStaticBitmapImage::Transfer() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   EnsureMailbox(kVerifiedSyncToken, GL_NEAREST);
+
+  // Release the SkiaTextureHolder, this SkImage is no longer valid to use
+  // cross-thread.
+  skia_texture_holder_.reset();
+
   DETACH_FROM_THREAD(thread_checker_);
 }
 
 bool AcceleratedStaticBitmapImage::CurrentFrameKnownToBeOpaque() {
-  return texture_holder_->CurrentFrameKnownToBeOpaque();
+  return texture_holder()->CurrentFrameKnownToBeOpaque();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h
index be932226..dd1b902 100644
--- a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h
+++ b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h
@@ -10,8 +10,9 @@
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_checker.h"
+#include "third_party/blink/renderer/platform/graphics/mailbox_texture_holder.h"
+#include "third_party/blink/renderer/platform/graphics/skia_texture_holder.h"
 #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
-#include "third_party/blink/renderer/platform/graphics/texture_holder.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 
 class GrContext;
@@ -23,7 +24,6 @@
 
 namespace blink {
 class WebGraphicsContext3DProviderWrapper;
-class TextureHolder;
 
 class PLATFORM_EXPORT AcceleratedStaticBitmapImage final
     : public StaticBitmapImage {
@@ -93,26 +93,25 @@
                      const IntPoint& dest_point,
                      const IntRect& source_sub_rectangle) override;
 
-  bool HasMailbox() const final {
-    return texture_holder_->IsMailboxTextureHolder();
-  }
+  bool HasMailbox() const final { return !!mailbox_texture_holder_; }
   // To be called on sender thread before performing a transfer
   void Transfer() final;
 
   void EnsureMailbox(MailboxSyncMode, GLenum filter) final;
 
   const gpu::Mailbox& GetMailbox() const final {
-    return texture_holder_->GetMailbox();
+    static const gpu::Mailbox mailbox;
+    return mailbox_texture_holder_ ? mailbox_texture_holder_->GetMailbox()
+                                   : mailbox;
   }
   const gpu::SyncToken& GetSyncToken() const final {
-    return texture_holder_->GetSyncToken();
+    static const gpu::SyncToken sync_token;
+    return mailbox_texture_holder_ ? mailbox_texture_holder_->GetSyncToken()
+                                   : sync_token;
   }
-  void UpdateSyncToken(gpu::SyncToken) final;
 
   PaintImage PaintImageForCurrentFrame() override;
 
-  TextureHolder* TextureHolderForTesting() { return texture_holder_.get(); }
-
  private:
   AcceleratedStaticBitmapImage(
       sk_sp<SkImage>,
@@ -138,7 +137,25 @@
   void WaitSyncTokenIfNeeded();
   void RetainOriginalSkImage();
 
-  std::unique_ptr<TextureHolder> texture_holder_;
+  // TODO(khushalsagar): Its unclear what to use here for calls checking IsValid
+  // or querying the ContextProvider for the image. This can differ in the 2,
+  // for instance if the image was transferred between threads.
+  const TextureHolder* texture_holder() const {
+    if (skia_texture_holder_)
+      return skia_texture_holder_.get();
+    return mailbox_texture_holder_.get();
+  }
+
+  // The image is created with one of the texture holders below while the other
+  // one is created lazily if needed and then persisted for the lifetime of the
+  // image on a particular thread.
+  // When Transfer is called, the image is detached from its current thread to
+  // allow it to be used on a different thread. We create(if needed) and cache
+  // the mailbox in this case, so the texture can be used with a different
+  // context. The skia texture holder is released since the mailbox needs to be
+  // imported into the GrContext on the new thread.
+  std::unique_ptr<SkiaTextureHolder> skia_texture_holder_;
+  std::unique_ptr<MailboxTextureHolder> mailbox_texture_holder_;
 
   THREAD_CHECKER(thread_checker_);
   PaintImage::ContentId paint_image_content_id_;
diff --git a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image_test.cc b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image_test.cc
index 120433e..42f4fab 100644
--- a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image_test.cc
+++ b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image_test.cc
@@ -77,21 +77,18 @@
   scoped_refptr<AcceleratedStaticBitmapImage> bitmap =
       AcceleratedStaticBitmapImage::CreateFromSkImage(image,
                                                       context_provider_wrapper);
-  EXPECT_TRUE(bitmap->TextureHolderForTesting()->IsSkiaTextureHolder());
 
   sk_sp<SkImage> stored_image =
       bitmap->PaintImageForCurrentFrame().GetSkImage();
   EXPECT_EQ(stored_image.get(), image.get());
 
   bitmap->EnsureMailbox(kUnverifiedSyncToken, GL_LINEAR);
-  EXPECT_TRUE(bitmap->TextureHolderForTesting()->IsMailboxTextureHolder());
 
   // Verify that calling PaintImageForCurrentFrame does not swap out of mailbox
   // mode. It should use the cached original image instead.
   stored_image = bitmap->PaintImageForCurrentFrame().GetSkImage();
 
   EXPECT_EQ(stored_image.get(), image.get());
-  EXPECT_TRUE(bitmap->TextureHolderForTesting()->IsMailboxTextureHolder());
 }
 
 TEST_F(AcceleratedStaticBitmapImageTest, CopyToTextureSynchronization) {
@@ -106,7 +103,6 @@
   scoped_refptr<AcceleratedStaticBitmapImage> bitmap =
       AcceleratedStaticBitmapImage::CreateFromSkImage(image,
                                                       context_provider_wrapper);
-  EXPECT_TRUE(bitmap->TextureHolderForTesting()->IsSkiaTextureHolder());
 
   MockGLES2InterfaceWithSyncTokenSupport destination_gl;
 
diff --git a/third_party/blink/renderer/platform/graphics/logging_canvas.cc b/third_party/blink/renderer/platform/graphics/logging_canvas.cc
index 79dbd08..2e8405e2 100644
--- a/third_party/blink/renderer/platform/graphics/logging_canvas.cc
+++ b/third_party/blink/renderer/platform/graphics/logging_canvas.cc
@@ -281,9 +281,7 @@
   }
 
   auto data_item = std::make_unique<JSONObject>();
-  data_item->SetString(
-      "base64",
-      WTF::Base64Encode(reinterpret_cast<char*>(output.data()), output.size()));
+  data_item->SetString("base64", Base64Encode(output));
   data_item->SetString("mimeType", "image/png");
   return data_item;
 }
diff --git a/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.cc b/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.cc
index 19ab2dd..7dc7769 100644
--- a/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.cc
+++ b/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.cc
@@ -74,14 +74,13 @@
 }
 
 MailboxTextureHolder::MailboxTextureHolder(
-    std::unique_ptr<TextureHolder> texture_holder,
+    const SkiaTextureHolder* texture_holder,
     GLenum filter)
     : TextureHolder(texture_holder->ContextProviderWrapper(),
                     texture_holder->IsOriginTopLeft()),
       texture_id_(0),
       is_converted_from_skia_texture_(true),
       thread_id_(0) {
-  DCHECK(texture_holder->IsSkiaTextureHolder());
   sk_sp<SkImage> image = texture_holder->GetSkImage();
   DCHECK(image);
   sk_image_info_ = image->imageInfo();
diff --git a/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.h b/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.h
index 9f0d7f9..63eb042 100644
--- a/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.h
+++ b/third_party/blink/renderer/platform/graphics/mailbox_texture_holder.h
@@ -16,29 +16,27 @@
 #include "third_party/skia/include/core/SkImageInfo.h"
 
 namespace blink {
+class SkiaTextureHolder;
 
 class PLATFORM_EXPORT MailboxTextureHolder final : public TextureHolder {
  public:
   ~MailboxTextureHolder() override;
 
-  bool IsSkiaTextureHolder() final { return false; }
-  bool IsMailboxTextureHolder() final { return true; }
+  // TextureHolder impl.
   IntSize Size() const final {
     return IntSize(sk_image_info_.width(), sk_image_info_.height());
   }
-  bool CurrentFrameKnownToBeOpaque() final { return false; }
+  bool CurrentFrameKnownToBeOpaque() const final { return false; }
   bool IsValid() const final;
-  bool IsCrossThread() const final;
 
-  const gpu::Mailbox& GetMailbox() const final { return mailbox_; }
-  const gpu::SyncToken& GetSyncToken() const final { return sync_token_; }
-  void UpdateSyncToken(gpu::SyncToken sync_token) final {
-    sync_token_ = sync_token;
-  }
+  bool IsCrossThread() const;
+  const gpu::Mailbox& GetMailbox() const { return mailbox_; }
+  const gpu::SyncToken& GetSyncToken() const { return sync_token_; }
+  void UpdateSyncToken(gpu::SyncToken sync_token) { sync_token_ = sync_token; }
   const SkImageInfo& sk_image_info() const { return sk_image_info_; }
   GLenum texture_target() const { return texture_target_; }
 
-  void Sync(MailboxSyncMode) final;
+  void Sync(MailboxSyncMode);
   // In WebGL's commit or transferToImageBitmap calls, it will call the
   // DrawingBuffer::transferToStaticBitmapImage function, which produces the
   // input parameters for this method.
@@ -50,7 +48,7 @@
                        bool is_origin_top_left);
   // This function turns a texture-backed SkImage into a mailbox and a
   // syncToken.
-  MailboxTextureHolder(std::unique_ptr<TextureHolder>, GLenum filter);
+  MailboxTextureHolder(const SkiaTextureHolder*, GLenum filter);
   // This function may be used when the MailboxTextureHolder is created on a
   // different thread. The caller must provide a verified sync token if it is
   // created cross-thread.
diff --git a/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc b/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc
index a8659fd..a486fe3 100644
--- a/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc
+++ b/third_party/blink/renderer/platform/graphics/skia_texture_holder.cc
@@ -33,15 +33,11 @@
       image_(std::move(image)) {}
 
 SkiaTextureHolder::SkiaTextureHolder(
-    std::unique_ptr<TextureHolder> texture_holder)
+    const MailboxTextureHolder* mailbox_texture_holder)
     : TextureHolder(SharedGpuContext::ContextProviderWrapper(),
-                    texture_holder->IsOriginTopLeft()) {
-  DCHECK(texture_holder->IsMailboxTextureHolder());
-  const gpu::Mailbox mailbox = texture_holder->GetMailbox();
-  const gpu::SyncToken sync_token = texture_holder->GetSyncToken();
-
-  auto* mailbox_texture_holder =
-      static_cast<MailboxTextureHolder*>(texture_holder.get());
+                    mailbox_texture_holder->IsOriginTopLeft()) {
+  const gpu::Mailbox mailbox = mailbox_texture_holder->GetMailbox();
+  const gpu::SyncToken sync_token = mailbox_texture_holder->GetSyncToken();
   const auto& sk_image_info = mailbox_texture_holder->sk_image_info();
   GLenum texture_target = mailbox_texture_holder->texture_target();
 
diff --git a/third_party/blink/renderer/platform/graphics/skia_texture_holder.h b/third_party/blink/renderer/platform/graphics/skia_texture_holder.h
index 33f51fd..0cfc9a3 100644
--- a/third_party/blink/renderer/platform/graphics/skia_texture_holder.h
+++ b/third_party/blink/renderer/platform/graphics/skia_texture_holder.h
@@ -12,22 +12,21 @@
 #include "third_party/blink/renderer/platform/platform_export.h"
 
 namespace blink {
-
+class MailboxTextureHolder;
 class WebGraphicsContext3DProviderWrapper;
 
 class PLATFORM_EXPORT SkiaTextureHolder final : public TextureHolder {
  public:
   ~SkiaTextureHolder() override;
 
-  // Methods overriding TextureHolder
-  bool IsSkiaTextureHolder() final { return true; }
-  bool IsMailboxTextureHolder() final { return false; }
+  // TextureHolder impl.
   IntSize Size() const final {
     return IntSize(image_->width(), image_->height());
   }
   bool IsValid() const final;
-  bool CurrentFrameKnownToBeOpaque() final { return image_->isOpaque(); }
-  sk_sp<SkImage> GetSkImage() final { return image_; }
+  bool CurrentFrameKnownToBeOpaque() const final { return image_->isOpaque(); }
+
+  const sk_sp<SkImage>& GetSkImage() const { return image_; }
 
   // When creating a AcceleratedStaticBitmap from a texture-backed SkImage, this
   // function will be called to create a TextureHolder object.
@@ -35,7 +34,7 @@
                     base::WeakPtr<WebGraphicsContext3DProviderWrapper>&&);
   // This function consumes the mailbox in the input parameter and turn it into
   // a texture-backed SkImage.
-  SkiaTextureHolder(std::unique_ptr<TextureHolder>);
+  explicit SkiaTextureHolder(const MailboxTextureHolder* texture_holder);
 
  private:
   // The image_ should always be texture-backed.
diff --git a/third_party/blink/renderer/platform/graphics/static_bitmap_image.h b/third_party/blink/renderer/platform/graphics/static_bitmap_image.h
index f35614d..399fe35 100644
--- a/third_party/blink/renderer/platform/graphics/static_bitmap_image.h
+++ b/third_party/blink/renderer/platform/graphics/static_bitmap_image.h
@@ -107,7 +107,6 @@
     return mailbox;
   }
   virtual const gpu::SyncToken& GetSyncToken() const;
-  virtual void UpdateSyncToken(gpu::SyncToken) { NOTREACHED(); }
   virtual bool IsPremultiplied() const { return true; }
 
   // Methods have exactly the same implementation for all sub-classes
diff --git a/third_party/blink/renderer/platform/graphics/texture_holder.h b/third_party/blink/renderer/platform/graphics/texture_holder.h
index 0e97f57d..e14fc6e7 100644
--- a/third_party/blink/renderer/platform/graphics/texture_holder.h
+++ b/third_party/blink/renderer/platform/graphics/texture_holder.h
@@ -23,32 +23,10 @@
   virtual ~TextureHolder() = default;
 
   // Methods overridden by all sub-classes
-  virtual bool IsSkiaTextureHolder() = 0;
-  virtual bool IsMailboxTextureHolder() = 0;
   virtual IntSize Size() const = 0;
-  virtual bool CurrentFrameKnownToBeOpaque() = 0;
+  virtual bool CurrentFrameKnownToBeOpaque() const = 0;
   virtual bool IsValid() const = 0;
 
-  // Methods overrided by MailboxTextureHolder
-  virtual const gpu::Mailbox& GetMailbox() const {
-    NOTREACHED();
-    static const gpu::Mailbox mailbox;
-    return mailbox;
-  }
-  virtual const gpu::SyncToken& GetSyncToken() const {
-    static const gpu::SyncToken sync_token;
-    return sync_token;
-  }
-  virtual void UpdateSyncToken(gpu::SyncToken) { NOTREACHED(); }
-  virtual void Sync(MailboxSyncMode) { NOTREACHED(); }
-  virtual bool IsCrossThread() const { return false; }
-
-  // Methods overridden by SkiaTextureHolder
-  virtual sk_sp<SkImage> GetSkImage() {
-    NOTREACHED();
-    return nullptr;
-  }
-
   // Methods that have exactly the same impelmentation for all sub-classes
   base::WeakPtr<WebGraphicsContext3DProviderWrapper> ContextProviderWrapper()
       const {
diff --git a/third_party/blink/renderer/platform/instrumentation/tracing/web_memory_allocator_dump.cc b/third_party/blink/renderer/platform/instrumentation/tracing/web_memory_allocator_dump.cc
index 758c465..e1e2417 100644
--- a/third_party/blink/renderer/platform/instrumentation/tracing/web_memory_allocator_dump.cc
+++ b/third_party/blink/renderer/platform/instrumentation/tracing/web_memory_allocator_dump.cc
@@ -25,8 +25,7 @@
 void WebMemoryAllocatorDump::AddString(const char* name,
                                        const char* units,
                                        const String& value) {
-  StringUTF8Adaptor adapter(value);
-  memory_allocator_dump_->AddString(name, units, adapter.AsStdString());
+  memory_allocator_dump_->AddString(name, units, value.Utf8());
 }
 
 WebMemoryAllocatorDumpGuid WebMemoryAllocatorDump::Guid() const {
diff --git a/third_party/blink/renderer/platform/instrumentation/tracing/web_process_memory_dump.cc b/third_party/blink/renderer/platform/instrumentation/tracing/web_process_memory_dump.cc
index f5c46937..bd9a898cb 100644
--- a/third_party/blink/renderer/platform/instrumentation/tracing/web_process_memory_dump.cc
+++ b/third_party/blink/renderer/platform/instrumentation/tracing/web_process_memory_dump.cc
@@ -35,10 +35,9 @@
 
 blink::WebMemoryAllocatorDump* WebProcessMemoryDump::CreateMemoryAllocatorDump(
     const String& absolute_name) {
-  StringUTF8Adaptor adapter(absolute_name);
   // Get a MemoryAllocatorDump from the base/ object.
   base::trace_event::MemoryAllocatorDump* memory_allocator_dump =
-      process_memory_dump_->CreateAllocatorDump(adapter.AsStdString());
+      process_memory_dump_->CreateAllocatorDump(absolute_name.Utf8());
 
   return CreateWebMemoryAllocatorDump(memory_allocator_dump);
 }
@@ -46,11 +45,10 @@
 blink::WebMemoryAllocatorDump* WebProcessMemoryDump::CreateMemoryAllocatorDump(
     const String& absolute_name,
     blink::WebMemoryAllocatorDumpGuid guid) {
-  StringUTF8Adaptor adapter(absolute_name);
   // Get a MemoryAllocatorDump from the base/ object with given guid.
   base::trace_event::MemoryAllocatorDump* memory_allocator_dump =
       process_memory_dump_->CreateAllocatorDump(
-          adapter.AsStdString(),
+          absolute_name.Utf8(),
           base::trace_event::MemoryAllocatorDumpGuid(guid));
   return CreateWebMemoryAllocatorDump(memory_allocator_dump);
 }
@@ -74,11 +72,10 @@
 
 blink::WebMemoryAllocatorDump* WebProcessMemoryDump::GetMemoryAllocatorDump(
     const String& absolute_name) const {
-  StringUTF8Adaptor adapter(absolute_name);
   // Retrieve the base MemoryAllocatorDump object and then reverse lookup
   // its wrapper.
   base::trace_event::MemoryAllocatorDump* memory_allocator_dump =
-      process_memory_dump_->GetAllocatorDump(adapter.AsStdString());
+      process_memory_dump_->GetAllocatorDump(absolute_name.Utf8());
   if (!memory_allocator_dump)
     return nullptr;
 
@@ -145,17 +142,15 @@
 void WebProcessMemoryDump::AddSuballocation(
     blink::WebMemoryAllocatorDumpGuid source,
     const String& target_node_name) {
-  StringUTF8Adaptor adapter(target_node_name);
   process_memory_dump_->AddSuballocation(
       base::trace_event::MemoryAllocatorDumpGuid(source),
-      adapter.AsStdString());
+      target_node_name.Utf8());
 }
 
 SkTraceMemoryDump* WebProcessMemoryDump::CreateDumpAdapterForSkia(
     const String& dump_name_prefix) {
-  StringUTF8Adaptor adapter(dump_name_prefix);
   sk_trace_dump_list_.push_back(std::make_unique<skia::SkiaTraceMemoryDumpImpl>(
-      adapter.AsStdString(), level_of_detail_, process_memory_dump_));
+      dump_name_prefix.Utf8(), level_of_detail_, process_memory_dump_));
   return sk_trace_dump_list_.back().get();
 }
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc b/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
index 14e59ed..80d91f2 100644
--- a/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
@@ -124,10 +124,13 @@
         ResourceFetcherInit(properties->MakeDetachable(), context,
                             base::MakeRefCounted<scheduler::FakeTaskRunner>(),
                             MakeGarbageCollected<TestLoaderFactory>()));
+    Resource::SetClockForTesting(platform_->test_task_runner()->GetMockClock());
   }
   void TearDown() override {
     GetMemoryCache()->EvictResources();
 
+    Resource::SetClockForTesting(nullptr);
+
     // Yield the ownership of the global memory cache back.
     ReplaceMemoryCacheForTesting(global_memory_cache_.Release());
   }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.cc b/third_party/blink/renderer/platform/loader/fetch/resource.cc
index 229888c5..78b141b 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource.cc
@@ -32,6 +32,7 @@
 
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/time/default_clock.h"
 #include "build/build_config.h"
 #include "services/network/public/mojom/fetch_api.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
@@ -56,7 +57,6 @@
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
-#include "third_party/blink/renderer/platform/wtf/time.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
@@ -119,6 +119,17 @@
   return true;
 }
 
+namespace {
+const base::Clock* g_clock_for_testing = nullptr;
+}
+
+static inline double Now() {
+  const base::Clock* clock = g_clock_for_testing
+                                 ? g_clock_for_testing
+                                 : base::DefaultClock::GetInstance();
+  return clock->Now().ToDoubleT();
+}
+
 Resource::Resource(const ResourceRequest& request,
                    ResourceType type,
                    const ResourceLoaderOptions& options)
@@ -134,7 +145,7 @@
       is_add_remove_client_prohibited_(false),
       integrity_disposition_(ResourceIntegrityDisposition::kNotChecked),
       options_(options),
-      response_timestamp_(CurrentTime()),
+      response_timestamp_(Now()),
       resource_request_(request),
       overhead_size_(CalculateOverheadSize()) {
   InstanceCounters::IncrementCounter(InstanceCounters::kResourceCounter);
@@ -377,7 +388,7 @@
   double corrected_received_age = std::isfinite(age_value)
                                       ? std::max(apparent_age, age_value)
                                       : apparent_age;
-  double resident_time = CurrentTime() - response_timestamp;
+  double resident_time = Now() - response_timestamp;
   return corrected_received_age + resident_time;
 }
 
@@ -489,7 +500,7 @@
 }
 
 void Resource::ResponseReceived(const ResourceResponse& response) {
-  response_timestamp_ = CurrentTime();
+  response_timestamp_ = Now();
   if (is_revalidating_) {
     if (response.HttpStatusCode() == 304) {
       RevalidationSucceeded(response);
@@ -1229,4 +1240,9 @@
   return false;
 }
 
+// static
+void Resource::SetClockForTesting(const base::Clock* clock) {
+  g_clock_for_testing = clock;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.h b/third_party/blink/renderer/platform/loader/fetch/resource.h
index 1377d01..a3c555c 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource.h
@@ -54,7 +54,10 @@
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/blink/renderer/platform/wtf/time.h"
+
+namespace base {
+class Clock;
+}
 
 namespace blink {
 
@@ -422,6 +425,9 @@
     return virtual_time_pauser_;
   }
 
+  // The caller owns the |clock| which must outlive the Resource.
+  static void SetClockForTesting(const base::Clock* clock);
+
  protected:
   Resource(const ResourceRequest&, ResourceType, const ResourceLoaderOptions&);
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 1a953c7a..a55cbc41 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -599,48 +599,11 @@
   return policy != kUse || resource->StillNeedsLoad();
 }
 
-void ResourceFetcher::RequestLoadStarted(uint64_t identifier,
-                                         Resource* resource,
-                                         const FetchParameters& params,
-                                         RevalidationPolicy policy,
-                                         bool is_static_data) {
-  KURL url = MemoryCache::RemoveFragmentIdentifierIfNeeded(params.Url());
-  if (policy == kUse && resource->GetStatus() == ResourceStatus::kCached &&
-      !cached_resources_map_.Contains(url)) {
-    // Loaded from MemoryCache.
-    DidLoadResourceFromMemoryCache(identifier, resource,
-                                   params.GetResourceRequest());
-  }
-
-  if (is_static_data)
-    return;
-
-  if (policy == kUse && !resource->StillNeedsLoad() &&
-      !cached_resources_map_.Contains(url)) {
-    // Resources loaded from memory cache should be reported the first time
-    // they're used.
-    scoped_refptr<ResourceTimingInfo> info = ResourceTimingInfo::Create(
-        params.Options().initiator_info.name, CurrentTimeTicks());
-    // TODO(yoav): GetInitialUrlForResourceTiming() is only needed until
-    // Out-of-Blink CORS lands: https://crbug.com/736308
-    info->SetInitialURL(
-        resource->GetResourceRequest().GetInitialUrlForResourceTiming().IsNull()
-            ? resource->GetResourceRequest().Url()
-            : resource->GetResourceRequest().GetInitialUrlForResourceTiming());
-    ResourceResponse final_response = resource->GetResponse();
-    final_response.SetResourceLoadTiming(nullptr);
-    info->SetFinalResponse(final_response);
-    info->SetLoadResponseEnd(info->InitialTime());
-    scheduled_resource_timing_reports_.push_back(std::move(info));
-    if (!resource_timing_report_timer_.IsActive())
-      resource_timing_report_timer_.StartOneShot(TimeDelta(), FROM_HERE);
-  }
-}
-
 void ResourceFetcher::DidLoadResourceFromMemoryCache(
     uint64_t identifier,
     Resource* resource,
-    const ResourceRequest& request) {
+    const ResourceRequest& request,
+    bool is_static_data) {
   if (IsDetached() || !resource_load_observer_)
     return;
 
@@ -658,6 +621,26 @@
   resource_load_observer_->DidFinishLoading(
       identifier, TimeTicks(), 0, resource->GetResponse().DecodedBodyLength(),
       false, ResourceLoadObserver::ResponseSource::kFromMemoryCache);
+
+  if (!is_static_data) {
+    // Resources loaded from memory cache should be reported the first time
+    // they're used.
+    scoped_refptr<ResourceTimingInfo> info = ResourceTimingInfo::Create(
+        resource->Options().initiator_info.name, CurrentTimeTicks());
+    // TODO(yoav): GetInitialUrlForResourceTiming() is only needed until
+    // Out-of-Blink CORS lands: https://crbug.com/736308
+    info->SetInitialURL(
+        resource->GetResourceRequest().GetInitialUrlForResourceTiming().IsNull()
+            ? resource->GetResourceRequest().Url()
+            : resource->GetResourceRequest().GetInitialUrlForResourceTiming());
+    ResourceResponse final_response = resource->GetResponse();
+    final_response.SetResourceLoadTiming(nullptr);
+    info->SetFinalResponse(final_response);
+    info->SetLoadResponseEnd(info->InitialTime());
+    scheduled_resource_timing_reports_.push_back(std::move(info));
+    if (!resource_timing_report_timer_.IsActive())
+      resource_timing_report_timer_.StartOneShot(TimeDelta(), FROM_HERE);
+  }
 }
 
 Resource* ResourceFetcher::ResourceForStaticData(
@@ -1075,7 +1058,13 @@
 
   // If only the fragment identifiers differ, it is the same resource.
   DCHECK(EqualIgnoringFragmentIdentifier(resource->Url(), params.Url()));
-  RequestLoadStarted(identifier, resource, params, policy, is_static_data);
+  if (policy == kUse && resource->GetStatus() == ResourceStatus::kCached &&
+      !cached_resources_map_.Contains(
+          MemoryCache::RemoveFragmentIdentifierIfNeeded(params.Url()))) {
+    // Loaded from MemoryCache.
+    DidLoadResourceFromMemoryCache(identifier, resource, resource_request,
+                                   is_static_data);
+  }
   if (!is_stale_revalidation) {
     String resource_url =
         MemoryCache::RemoveFragmentIdentifierIfNeeded(params.Url());
@@ -2033,7 +2022,9 @@
                        resource->LastResourceRequest().Url(), params.Options(),
                        SecurityViolationReportingPolicy::kReport,
                        resource->LastResourceRequest().GetRedirectStatus());
-  RequestLoadStarted(resource->InspectorId(), resource, params, kUse);
+  DidLoadResourceFromMemoryCache(resource->InspectorId(), resource,
+                                 params.GetResourceRequest(),
+                                 false /* is_static_data */);
 }
 
 void ResourceFetcher::PrepareForLeakDetection() {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
index d8cec98..c2e1829 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
@@ -348,15 +348,10 @@
   void MoveResourceLoaderToNonBlocking(ResourceLoader*);
   void RemoveResourceLoader(ResourceLoader*);
 
-  void RequestLoadStarted(uint64_t identifier,
-                          Resource*,
-                          const FetchParameters&,
-                          RevalidationPolicy,
-                          bool is_static_data = false);
-
   void DidLoadResourceFromMemoryCache(uint64_t identifier,
                                       Resource*,
-                                      const ResourceRequest&);
+                                      const ResourceRequest&,
+                                      bool is_static_data);
 
   bool ResourceNeedsLoad(Resource*, const FetchParameters&, RevalidationPolicy);
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
index c743e4de28..55b6018e 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
@@ -500,8 +500,17 @@
   EXPECT_FALSE(resource->IsAlive());
 }
 
+class ScopedResourceMockClock {
+ public:
+  explicit ScopedResourceMockClock(const base::Clock* clock) {
+    Resource::SetClockForTesting(clock);
+  }
+  ~ScopedResourceMockClock() { Resource::SetClockForTesting(nullptr); }
+};
+
 TEST(ResourceTest, StaleWhileRevalidateCacheControl) {
   ScopedTestingPlatformSupport<MockPlatform> mock;
+  ScopedResourceMockClock clock(mock->test_task_runner()->GetMockClock());
   const KURL url("http://127.0.0.1:8000/foo.html");
   ResourceResponse response(url);
   response.SetHttpStatusCode(200);
@@ -529,6 +538,7 @@
 
 TEST(ResourceTest, StaleWhileRevalidateCacheControlWithRedirect) {
   ScopedTestingPlatformSupport<MockPlatform> mock;
+  ScopedResourceMockClock clock(mock->test_task_runner()->GetMockClock());
   const KURL url("http://127.0.0.1:8000/foo.html");
   const KURL redirect_target_url("http://127.0.0.1:8000/food.html");
   ResourceResponse response(url);
diff --git a/third_party/blink/renderer/platform/loader/subresource_integrity.cc b/third_party/blink/renderer/platform/loader/subresource_integrity.cc
index a930d435d..ff660e4 100644
--- a/third_party/blink/renderer/platform/loader/subresource_integrity.cc
+++ b/third_party/blink/renderer/platform/loader/subresource_integrity.cc
@@ -52,11 +52,6 @@
   return IsASCIISpace(c) || c == ',';
 }
 
-static String DigestToString(const DigestValue& digest) {
-  return Base64Encode(reinterpret_cast<const char*>(digest.data()),
-                      digest.size(), kBase64DoNotInsertLFs);
-}
-
 void SubresourceIntegrity::ReportInfo::AddUseCount(UseCounterFeature feature) {
   use_counts_.push_back(feature);
 }
@@ -163,7 +158,7 @@
         "Failed to find a valid digest in the 'integrity' attribute for "
         "resource '" +
         resource_url.ElidedString() + "' with computed SHA-256 integrity '" +
-        DigestToString(digest) + "'. The resource has been blocked.");
+        Base64Encode(digest) + "'. The resource has been blocked.");
   } else {
     report_info.AddConsoleErrorMessage(
         "There was an error computing an integrity value for resource '" +
diff --git a/third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.cc b/third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.cc
index 9fc9306..d1ddf22 100644
--- a/third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.cc
+++ b/third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.cc
@@ -29,13 +29,10 @@
       scheduler_->CreateMainThread());
   // Set the work batch size to one so TakePendingTasks behaves as expected.
   scheduler_->GetSchedulerHelperForTesting()->SetWorkBatchSizeForTesting(1);
-
-  WTF::SetTimeFunctionsForTesting(GetTestTime);
 }
 
 TestingPlatformSupportWithMockScheduler::
     ~TestingPlatformSupportWithMockScheduler() {
-  WTF::SetTimeFunctionsForTesting(nullptr);
   scheduler_->Shutdown();
 }
 
@@ -92,13 +89,4 @@
   return scheduler_.get();
 }
 
-// static
-double TestingPlatformSupportWithMockScheduler::GetTestTime() {
-  TestingPlatformSupportWithMockScheduler* platform =
-      static_cast<TestingPlatformSupportWithMockScheduler*>(
-          Platform::Current());
-  return (platform->test_task_runner_->NowTicks() - base::TimeTicks())
-      .InSecondsF();
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/timer_test.cc b/third_party/blink/renderer/platform/timer_test.cc
index aaa2bcb..f2e4b64 100644
--- a/third_party/blink/renderer/platform/timer_test.cc
+++ b/third_party/blink/renderer/platform/timer_test.cc
@@ -17,7 +17,6 @@
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
-#include "third_party/blink/renderer/platform/wtf/time.h"
 
 using base::sequence_manager::TaskQueue;
 using blink::scheduler::MainThreadTaskQueue;
@@ -39,17 +38,19 @@
   void SetUp() override {
     run_times_.clear();
     platform_->AdvanceClock(TimeDelta::FromSeconds(10));
-    start_time_ = CurrentTimeTicks();
+    start_time_ = Now();
   }
 
-  void CountingTask(TimerBase*) { run_times_.push_back(CurrentTimeTicks()); }
+  base::TimeTicks Now() { return platform_->test_task_runner()->NowTicks(); }
+
+  void CountingTask(TimerBase*) { run_times_.push_back(Now()); }
 
   void RecordNextFireTimeTask(TimerBase* timer) {
-    next_fire_times_.push_back(CurrentTimeTicks() + timer->NextFireInterval());
+    next_fire_times_.push_back(Now() + timer->NextFireInterval());
   }
 
   void RunUntilDeadline(TimeTicks deadline) {
-    TimeDelta period = deadline - CurrentTimeTicks();
+    TimeDelta period = deadline - Now();
     EXPECT_GE(period, TimeDelta());
     platform_->RunForPeriod(period);
   }
@@ -250,7 +251,7 @@
   platform_->RunUntilIdle();
   EXPECT_FALSE(run_times_.size());
 
-  TimeTicks second_post_time = CurrentTimeTicks();
+  TimeTicks second_post_time = Now();
   timer.StartOneShot(TimeDelta::FromSeconds(10), FROM_HERE);
 
   EXPECT_TRUE(TimeTillNextDelayedTask(&run_time));
@@ -554,7 +555,7 @@
   // Simulate timer firing early. Next scheduled task to run at
   // |start_time_| + 4s
   platform_->AdvanceClock(TimeDelta::FromMilliseconds(1900));
-  RunUntilDeadline(CurrentTimeTicks() + TimeDelta::FromMilliseconds(200));
+  RunUntilDeadline(Now() + TimeDelta::FromMilliseconds(200));
 
   // Next scheduled task to run at |start_time_| + 6s
   platform_->RunForPeriod(TimeDelta::FromSeconds(2));
@@ -716,7 +717,7 @@
 
   TimerForTest<TimerTest> timer(task_runner1, this, &TimerTest::CountingTask);
 
-  TimeTicks start_time = CurrentTimeTicks();
+  TimeTicks start_time = Now();
 
   timer.StartOneShot(TimeDelta::FromSeconds(1), FROM_HERE);
 
@@ -757,7 +758,7 @@
 
   TimerForTest<TimerTest> timer(task_runner1, this, &TimerTest::CountingTask);
 
-  TimeTicks start_time = CurrentTimeTicks();
+  TimeTicks start_time = Now();
 
   timer.StartRepeating(TimeDelta::FromSeconds(1), FROM_HERE);
 
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin.cc b/third_party/blink/renderer/platform/weborigin/security_origin.cc
index 9c5f809..006236a5 100644
--- a/third_party/blink/renderer/platform/weborigin/security_origin.cc
+++ b/third_party/blink/renderer/platform/weborigin/security_origin.cc
@@ -246,10 +246,8 @@
 
 url::Origin SecurityOrigin::ToUrlOrigin() const {
   const SecurityOrigin* unmasked = GetOriginOrPrecursorOriginIfOpaque();
-  std::string scheme =
-      StringUTF8Adaptor(unmasked->protocol_).AsStringPiece().as_string();
-  std::string host =
-      StringUTF8Adaptor(unmasked->host_).AsStringPiece().as_string();
+  std::string scheme = unmasked->protocol_.Utf8();
+  std::string host = unmasked->host_.Utf8();
   uint16_t port = unmasked->effective_port_;
   if (nonce_if_opaque_) {
     url::Origin result = url::Origin::CreateOpaqueFromNormalizedPrecursorTuple(
diff --git a/third_party/blink/renderer/platform/wtf/text/base64.cc b/third_party/blink/renderer/platform/wtf/text/base64.cc
index b73c6b5..94f22eef1 100644
--- a/third_party/blink/renderer/platform/wtf/text/base64.cc
+++ b/third_party/blink/renderer/platform/wtf/text/base64.cc
@@ -49,11 +49,10 @@
     0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
     0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00};
 
-String Base64Encode(const char* data,
-                    unsigned length,
-                    Base64EncodePolicy policy) {
+String Base64Encode(base::span<const uint8_t> data, Base64EncodePolicy policy) {
   Vector<char> result;
-  Base64Encode(data, length, result, policy);
+  Base64Encode(reinterpret_cast<const char*>(data.data()), data.size(), result,
+               policy);
   return String(result.data(), result.size());
 }
 
@@ -273,7 +272,9 @@
 String Base64URLEncode(const char* data,
                        unsigned length,
                        Base64EncodePolicy policy) {
-  return Base64Encode(data, length, policy).Replace('+', '-').Replace('/', '_');
+  return Base64Encode(base::as_bytes(base::make_span(data, length)), policy)
+      .Replace('+', '-')
+      .Replace('/', '_');
 }
 
 String NormalizeToBase64(const String& encoding) {
diff --git a/third_party/blink/renderer/platform/wtf/text/base64.h b/third_party/blink/renderer/platform/wtf/text/base64.h
index e221b528..5ba04f2 100644
--- a/third_party/blink/renderer/platform/wtf/text/base64.h
+++ b/third_party/blink/renderer/platform/wtf/text/base64.h
@@ -47,13 +47,6 @@
 WTF_EXPORT void Base64Encode(const std::string&,
                              Vector<char>&,
                              Base64EncodePolicy = kBase64DoNotInsertLFs);
-WTF_EXPORT String Base64Encode(const char*,
-                               unsigned,
-                               Base64EncodePolicy = kBase64DoNotInsertLFs);
-WTF_EXPORT String Base64Encode(const Vector<char>&,
-                               Base64EncodePolicy = kBase64DoNotInsertLFs);
-WTF_EXPORT String Base64Encode(const Vector<unsigned char>&,
-                               Base64EncodePolicy = kBase64DoNotInsertLFs);
 WTF_EXPORT String Base64Encode(base::span<const uint8_t>,
                                Base64EncodePolicy = kBase64DoNotInsertLFs);
 
@@ -105,22 +98,6 @@
   Base64Encode(in.c_str(), static_cast<unsigned>(in.length()), out, policy);
 }
 
-inline String Base64Encode(const Vector<char>& in, Base64EncodePolicy policy) {
-  return Base64Encode(in.data(), in.size(), policy);
-}
-
-inline String Base64Encode(const Vector<unsigned char>& in,
-                           Base64EncodePolicy policy) {
-  return Base64Encode(reinterpret_cast<const char*>(in.data()), in.size(),
-                      policy);
-}
-
-inline String Base64Encode(base::span<const uint8_t> in,
-                           Base64EncodePolicy policy) {
-  return Base64Encode(reinterpret_cast<const char*>(in.data()),
-                      static_cast<unsigned>(in.size()), policy);
-}
-
 }  // namespace WTF
 
 using WTF::Base64EncodePolicy;
diff --git a/third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h b/third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h
index 05eabe5..443617c6ce 100644
--- a/third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h
+++ b/third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h
@@ -56,12 +56,6 @@
     return base::StringPiece(data_, size_);
   }
 
-  std::string AsStdString() {
-    // TODO(dcheng): it might be nice to store a std::string and avoid the
-    // double conversion...
-    return std::string(data_, size_);
-  }
-
  private:
   std::string utf8_buffer_;
   const char* data_ = nullptr;
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
index 9c99b74..21bc42b 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
@@ -90,6 +90,7 @@
 crbug.com/591099 external/wpt/css/css-contain/contain-layout-baseline-005.html [ Pass ]
 crbug.com/714962 external/wpt/css/css-fonts/font-features-across-space-1.html [ Pass ]
 crbug.com/714962 external/wpt/css/css-fonts/font-features-across-space-3.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-fonts/math-script-level-and-math-style/math-script-level-font-size-clamping-001.tentative.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-003.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-span-all-list-item-002.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-overflow/webkit-line-clamp-026.html [ Failure ]
@@ -110,6 +111,7 @@
 crbug.com/591099 external/wpt/css/css-rhythm/ [ Skip ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-017.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-018.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-sizing/clone-nowrap-intrinsic-size-bidi.html [ Pass ]
 crbug.com/845902 external/wpt/css/css-sizing/whitespace-and-break.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/boundary-shaping/boundary-shaping-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/boundary-shaping/boundary-shaping-003.html [ Pass ]
@@ -166,8 +168,6 @@
 crbug.com/591099 external/wpt/css/css-text/white-space/line-edge-white-space-collapse-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/white-space/line-edge-white-space-collapse-002.html [ Pass ]
 crbug.com/40634 external/wpt/css/css-text/white-space/trailing-space-before-br-001.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-text/white-space/white-space-intrinsic-size-004.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-002.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/word-break/word-break-break-all-004.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/word-break/word-break-break-all-inline-006.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-transitions/no-transition-from-ua-to-blocking-stylesheet.html [ Failure Pass ]
@@ -291,31 +291,30 @@
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-margin-box-border-radius-008.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-padding-box-border-radius-002.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/hori-block-size-small-or-larger-than-container-with-min-or-max-content-1.html [ Pass ]
+crbug.com/591099 external/wpt/dom/ranges/Range-compareBoundaryPoints.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Pass ]
 crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html/user-activation/activation-transfer-without-click.tentative.html [ Pass ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch.html [ Pass ]
-crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch.html [ Failure Pass ]
+crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch.html [ Pass ]
 crbug.com/845902 external/wpt/quirks/line-height-trailing-collapsable-whitespace.html [ Pass ]
 crbug.com/591099 external/wpt/referrer-policy/no-referrer/http-rp/same-origin/http-http/shared-worker/keep-origin-redirect/generic.http.html [ Pass ]
 crbug.com/591099 external/wpt/referrer-policy/no-referrer/http-rp/same-origin/http-http/shared-worker/no-redirect/generic.http.html [ Pass ]
 crbug.com/591099 external/wpt/referrer-policy/no-referrer/meta-referrer/same-origin/http-http/shared-worker/keep-origin-redirect/generic.http.html [ Pass ]
 crbug.com/591099 external/wpt/referrer-policy/no-referrer/meta-referrer/same-origin/http-http/shared-worker/no-redirect/generic.http.html [ Pass ]
-crbug.com/591099 external/wpt/service-workers/service-worker/update-registration-with-type.https.html [ Pass ]
 crbug.com/591099 external/wpt/webauthn/createcredential-extensions.https.html [ Pass ]
 crbug.com/591099 external/wpt/webrtc/RTCIceConnectionState-candidate-pair.https.html [ Pass ]
 crbug.com/591099 fast/backgrounds/quirks-mode-line-box-backgrounds.html [ Failure ]
 crbug.com/591099 fast/block/float/4145535Crash.html [ Pass ]
 crbug.com/591099 fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ Failure ]
-crbug.com/591099 fast/canvas/OffscreenCanvas-copyImage.html [ Failure Pass ]
+crbug.com/591099 fast/canvas/OffscreenCanvas-copyImage.html [ Pass ]
 crbug.com/591099 fast/css/absolute-inline-alignment-2.html [ Pass ]
 crbug.com/835484 fast/css/outline-narrowLine.html [ Failure ]
 crbug.com/591099 fast/css/outline-offset-large.html [ Failure ]
 crbug.com/855279 fast/css/text-overflow-ellipsis-vertical-hittest.html [ Pass ]
 crbug.com/591099 fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under.html [ Failure ]
 crbug.com/591099 fast/dom/timer-throttling-out-of-view-cross-origin-page.html [ Failure Pass ]
-crbug.com/591099 fast/events/before-unload-return-value-from-listener.html [ Pass ]
-crbug.com/591099 fast/events/pointerevents/multi-touch-events.html [ Failure Pass ]
+crbug.com/591099 fast/events/before-unload-return-value-from-listener.html [ Crash Pass ]
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects-continuation.html [ Failure ]
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects-list-translate.html [ Failure ]
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
@@ -324,7 +323,7 @@
 crbug.com/591099 fast/multicol/border-radius-clipped-layer.html [ Pass ]
 crbug.com/591099 fast/overflow/overflow-height-float-not-removed-crash3.html [ Failure ]
 crbug.com/591099 fast/peerconnection/RTCPeerConnection-many.html [ Pass ]
-crbug.com/591099 fast/replaced/replaced-breaking.html [ Failure Pass ]
+crbug.com/591099 fast/replaced/replaced-breaking.html [ Failure ]
 crbug.com/899902 fast/text/ellipsis-with-self-painting-layer.html [ Pass ]
 crbug.com/591099 fast/text/emoji-vertical-origin-visual.html [ Failure ]
 crbug.com/591099 fast/text/font-format-support-color-cff2-vertical.html [ Failure ]
@@ -335,7 +334,9 @@
 crbug.com/591099 fast/writing-mode/percentage-height-orthogonal-writing-modes.html [ Failure ]
 crbug.com/591099 fast/writing-mode/table-percent-width-quirk.html [ Pass ]
 crbug.com/591099 http/tests/appcache/non-html.xhtml [ Crash Pass ]
+crbug.com/591099 http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html [ Failure Pass ]
 crbug.com/591099 http/tests/csspaint/invalidation-border-image.html [ Pass ]
+crbug.com/591099 http/tests/devtools/audits/audits-successful-run.js [ Failure ]
 crbug.com/591099 http/tests/devtools/sources/debugger-frameworks/frameworks-jquery.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/tracing-session-id.js [ Pass ]
 crbug.com/591099 http/tests/devtools/tracing/console-timeline.js [ Pass ]
@@ -368,7 +369,7 @@
 crbug.com/591099 virtual/exotic-color-space/ [ Skip ]
 crbug.com/591099 virtual/fractional_scrolling_threaded/fast/scrolling/unscrollable-layer-subpixel-size-with-negative-overflow.html [ Failure Pass ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-image-filter-all.html [ Pass ]
-crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-copyImage.html [ Pass ]
+crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-copyImage.html [ Failure Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-filter.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-arc-circumference.html [ Failure ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-blend-image.html [ Pass ]
@@ -384,12 +385,12 @@
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-list-translate.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
 crbug.com/591099 virtual/new-remote-playback-pipeline/ [ Skip ]
-crbug.com/591099 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/update-registration-with-type.https.html [ Pass ]
 crbug.com/591099 virtual/paint-timing/external/wpt/paint-timing/sibling-painting-first-image.html [ Failure ]
 crbug.com/591099 virtual/prefer_compositing_to_lcd_text/ [ Skip ]
 crbug.com/591099 virtual/scalefactor200/css3/filters/backdrop-filter-svg.html [ Pass ]
 crbug.com/591099 virtual/scalefactor200/css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change.html [ Failure ]
 crbug.com/591099 virtual/scalefactor200/external/wpt/css/filter-effects/filtered-inline-applies-to-float.html [ Pass ]
+crbug.com/591099 virtual/scalefactor200/external/wpt/css/filter-effects/filters-test-brightness-003.html [ Pass ]
 crbug.com/591099 virtual/scroll_customization/ [ Skip ]
 crbug.com/591099 virtual/stable/ [ Skip ]
 crbug.com/591099 virtual/streams-native/external/wpt/fetch/api/basic/error-after-response.html [ Pass ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index fae176a..a3f635f 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2836,6 +2836,19 @@
 crbug.com/968164 external/wpt/css/css-ui/webkit-appearance-menulist-button-002.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Retina ] external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-top-left.html [ Timeout ]
+crbug.com/626703 external/wpt/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html [ Timeout ]
+crbug.com/626703 virtual/feature-policy-permissions/external/wpt/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html [ Timeout ]
+crbug.com/626703 [ Linux ] external/wpt/html/cross-origin/anonymous.tentative.html [ Crash ]
+crbug.com/626703 [ Mac10.12 ] external/wpt/html/cross-origin/anonymous.tentative.html [ Crash ]
+crbug.com/626703 [ Mac10.11 ] external/wpt/html/cross-origin/anonymous.tentative.html [ Failure Crash ]
+crbug.com/626703 [ Mac10.13 ] external/wpt/html/cross-origin/anonymous.tentative.html [ Failure Crash ]
+crbug.com/626703 [ Retina ] external/wpt/html/cross-origin/anonymous.tentative.html [ Failure Crash ]
+crbug.com/626703 [ Win10 ] external/wpt/html/cross-origin/anonymous.tentative.html [ Failure Crash ]
+crbug.com/626703 [ Win7 ] external/wpt/html/cross-origin/anonymous.tentative.html [ Failure Crash ]
+crbug.com/626703 external/wpt/css/css-multicol/multicol-span-all-011.html [ Failure ]
+crbug.com/699040 external/wpt/svg/text/reftests/text-xml-space-001.svg [ Failure ]
+crbug.com/626703 virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-span-all-011.html [ Failure ]
 crbug.com/626703 external/wpt/css/CSS2/abspos/hypothetical-box-dynamic.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-sizing/clone-nowrap-intrinsic-size-bidi.html [ Failure ]
 crbug.com/626703 external/wpt/service-workers/service-worker/ready.https.html [ Timeout ]
@@ -5388,6 +5401,7 @@
 crbug.com/922951 fast/scroll-snap/snaps-for-different-key-granularity.html [ Skip ]
 crbug.com/922951 fast/text/international/inline-plaintext-relayout-with-leading-neutrals.html [ Skip ]
 crbug.com/922951 http/tests/cache/subresource-fragment-identifier.html [ Skip ]
+crbug.com/922951 http/tests/devtools/audits/audits-successful-run.js [ Skip ]
 crbug.com/922951 http/tests/devtools/tracing-session-id.js [ Skip ]
 crbug.com/922951 http/tests/devtools/tracing/console-timeline.js [ Skip ]
 crbug.com/922951 http/tests/devtools/tracing/timeline-network-received-data.js [ Skip ]
@@ -5842,3 +5856,15 @@
 
 # Sheriff 2019-06-13
 crbug.com/973692 [ Mac ] external/wpt/css/css-text/parsing/hyphens-computed.html [ Failure ]
+crbug.com/973726 [ Mac ] fast/css/large-list-of-rules-crash.html [ Pass Timeout ]
+crbug.com/937546 [ Win7 ] http/tests/security/xss-DENIED-cross-origin-stack-overflow.html [ Pass Timeout ]
+crbug.com/937546 [ Win7 ] virtual/blink-cors/http/tests/security/xss-DENIED-cross-origin-stack-overflow.html [ Pass Timeout ]
+
+# Flaky on Linux
+crbug.com/973769 [ Linux ] http/tests/media/video-seek-to-duration.html [ Pass Failure ]
+crbug.com/973769 [ Linux ] http/tests/media/video-seek-to-middle.html [ Pass Failure ]
+crbug.com/973769 [ Linux ] media/controls/controls-cast-do-not-fade-out.html [ Pass Timeout ]
+crbug.com/973769 [ Linux ] media/video-pause-immediately.html [ Pass Failure ]
+crbug.com/973769 [ Linux ] media/video-played-ranges-1.html [ Pass Failure ]
+crbug.com/973769 [ Linux ] media/video-played-reset.html [ Pass Failure ]
+crbug.com/973769 [ Linux ] media/W3C/audio/events/event_timeupdate_manual.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index 9f7f6e1d..0f9141b9 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -56435,6 +56435,18 @@
      {}
     ]
    ],
+   "css/css-multicol/multicol-span-all-011.html": [
+    [
+     "css/css-multicol/multicol-span-all-011.html",
+     [
+      [
+       "/css/css-multicol/multicol-span-all-011-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-multicol/multicol-span-all-block-sibling-003.xht": [
     [
      "css/css-multicol/multicol-span-all-block-sibling-003.xht",
@@ -114417,18 +114429,6 @@
      {}
     ]
    ],
-   "mathml/relations/css-styling/lengths-2.html": [
-    [
-     "mathml/relations/css-styling/lengths-2.html",
-     [
-      [
-       "/mathml/relations/css-styling/lengths-2-ref.html",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
    "mathml/relations/css-styling/mathvariant-bold-fraktur.html": [
     [
      "mathml/relations/css-styling/mathvariant-bold-fraktur.html",
@@ -116469,6 +116469,18 @@
      {}
     ]
    ],
+   "svg/text/reftests/text-xml-space-001.svg": [
+    [
+     "svg/text/reftests/text-xml-space-001.svg",
+     [
+      [
+       "/svg/text/reftests/text-xml-space-001-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "svg/text/reftests/textpath-shape-001.svg": [
     [
      "svg/text/reftests/textpath-shape-001.svg",
@@ -137276,6 +137288,9 @@
    "css/css-multicol/multicol-span-all-010-ref.html": [
     []
    ],
+   "css/css-multicol/multicol-span-all-011-ref.html": [
+    []
+   ],
    "css/css-multicol/multicol-span-all-block-sibling-3-ref.xht": [
     []
    ],
@@ -147794,9 +147809,6 @@
    "custom-elements/resources/navigation-destination.html": [
     []
    ],
-   "custom-elements/upgrading-expected.txt": [
-    []
-   ],
    "custom-elements/upgrading/Node-cloneNode-expected.txt": [
     []
    ],
@@ -152390,6 +152402,45 @@
    "html/cross-origin-opener/resources/window.sub.html.headers": [
     []
    ],
+   "html/cross-origin/anonymous.tentative.html.headers": [
+    []
+   ],
+   "html/cross-origin/null.tentative.html.headers": [
+    []
+   ],
+   "html/cross-origin/resources/navigate_anonymous.sub.html": [
+    []
+   ],
+   "html/cross-origin/resources/navigate_anonymous.sub.html.headers": [
+    []
+   ],
+   "html/cross-origin/resources/navigate_null.sub.html": [
+    []
+   ],
+   "html/cross-origin/resources/navigate_usecredentials.sub.html": [
+    []
+   ],
+   "html/cross-origin/resources/navigate_usecredentials.sub.html.headers": [
+    []
+   ],
+   "html/cross-origin/resources/nothing.txt": [
+    []
+   ],
+   "html/cross-origin/resources/nothing.txt.headers": [
+    []
+   ],
+   "html/cross-origin/resources/popup_and_close.sub.html": [
+    []
+   ],
+   "html/cross-origin/resources/popup_and_close.sub.html.headers": [
+    []
+   ],
+   "html/cross-origin/usecredentials.tentative-expected.txt": [
+    []
+   ],
+   "html/cross-origin/usecredentials.tentative.html.headers": [
+    []
+   ],
    "html/dom/documents/dom-tree-accessors/OWNERS": [
     []
    ],
@@ -159470,9 +159521,6 @@
    "mathml/relations/css-styling/lengths-1-ref.html": [
     []
    ],
-   "mathml/relations/css-styling/lengths-2-ref.html": [
-    []
-   ],
    "mathml/relations/css-styling/mathvariant-bold-fraktur-ref.html": [
     []
    ],
@@ -160004,6 +160052,9 @@
    "mediacapture-streams/META.yml": [
     []
    ],
+   "mediacapture-streams/MediaStream-MediaElement-firstframe.https-expected.txt": [
+    []
+   ],
    "mediacapture-streams/MediaStream-MediaElement-preload-none.https-expected.txt": [
     []
    ],
@@ -166802,6 +166853,9 @@
    "svg/text/reftests/text-text-anchor-203-ref.svg": [
     []
    ],
+   "svg/text/reftests/text-xml-space-001-ref.svg": [
+    []
+   ],
    "svg/text/reftests/textpath-shape-001-ref.svg": [
     []
    ],
@@ -166829,6 +166883,12 @@
    "svg/types/scripted/resources/SVGLengthList-helper.js": [
     []
    ],
+   "timing-entrytypes-registry/META.yml": [
+    []
+   ],
+   "timing-entrytypes-registry/resources/utils.js": [
+    []
+   ],
    "tools/META.yml": [
     []
    ],
@@ -172091,6 +172151,9 @@
    "webrtc/RTCPeerConnection-iceGatheringState-expected.txt": [
     []
    ],
+   "webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt": [
+    []
+   ],
    "webrtc/RTCPeerConnection-ondatachannel-expected.txt": [
     []
    ],
@@ -196696,6 +196759,12 @@
      {}
     ]
    ],
+   "css/css-backgrounds/parsing/border-color-computed.html": [
+    [
+     "css/css-backgrounds/parsing/border-color-computed.html",
+     {}
+    ]
+   ],
    "css/css-backgrounds/parsing/border-color-invalid.html": [
     [
      "css/css-backgrounds/parsing/border-color-invalid.html",
@@ -196714,6 +196783,12 @@
      {}
     ]
    ],
+   "css/css-backgrounds/parsing/border-image-outset-computed.html": [
+    [
+     "css/css-backgrounds/parsing/border-image-outset-computed.html",
+     {}
+    ]
+   ],
    "css/css-backgrounds/parsing/border-image-outset-invalid.html": [
     [
      "css/css-backgrounds/parsing/border-image-outset-invalid.html",
@@ -196726,6 +196801,12 @@
      {}
     ]
    ],
+   "css/css-backgrounds/parsing/border-image-repeat-computed.html": [
+    [
+     "css/css-backgrounds/parsing/border-image-repeat-computed.html",
+     {}
+    ]
+   ],
    "css/css-backgrounds/parsing/border-image-repeat-invalid.html": [
     [
      "css/css-backgrounds/parsing/border-image-repeat-invalid.html",
@@ -196738,6 +196819,12 @@
      {}
     ]
    ],
+   "css/css-backgrounds/parsing/border-image-slice-computed.html": [
+    [
+     "css/css-backgrounds/parsing/border-image-slice-computed.html",
+     {}
+    ]
+   ],
    "css/css-backgrounds/parsing/border-image-slice-invalid.html": [
     [
      "css/css-backgrounds/parsing/border-image-slice-invalid.html",
@@ -196750,6 +196837,12 @@
      {}
     ]
    ],
+   "css/css-backgrounds/parsing/border-image-source-computed.html": [
+    [
+     "css/css-backgrounds/parsing/border-image-source-computed.html",
+     {}
+    ]
+   ],
    "css/css-backgrounds/parsing/border-image-source-invalid.html": [
     [
      "css/css-backgrounds/parsing/border-image-source-invalid.html",
@@ -196768,6 +196861,12 @@
      {}
     ]
    ],
+   "css/css-backgrounds/parsing/border-image-width-computed.html": [
+    [
+     "css/css-backgrounds/parsing/border-image-width-computed.html",
+     {}
+    ]
+   ],
    "css/css-backgrounds/parsing/border-image-width-invalid.html": [
     [
      "css/css-backgrounds/parsing/border-image-width-invalid.html",
@@ -196798,6 +196897,12 @@
      {}
     ]
    ],
+   "css/css-backgrounds/parsing/border-style-computed.html": [
+    [
+     "css/css-backgrounds/parsing/border-style-computed.html",
+     {}
+    ]
+   ],
    "css/css-backgrounds/parsing/border-style-invalid.html": [
     [
      "css/css-backgrounds/parsing/border-style-invalid.html",
@@ -196816,6 +196921,12 @@
      {}
     ]
    ],
+   "css/css-backgrounds/parsing/border-width-computed.html": [
+    [
+     "css/css-backgrounds/parsing/border-width-computed.html",
+     {}
+    ]
+   ],
    "css/css-backgrounds/parsing/border-width-invalid.html": [
     [
      "css/css-backgrounds/parsing/border-width-invalid.html",
@@ -201592,6 +201703,12 @@
      {}
     ]
    ],
+   "css/css-position/position-absolute-chrome-bug-001.html": [
+    [
+     "css/css-position/position-absolute-chrome-bug-001.html",
+     {}
+    ]
+   ],
    "css/css-position/position-absolute-container-dynamic-002.html": [
     [
      "css/css-position/position-absolute-container-dynamic-002.html",
@@ -205702,6 +205819,12 @@
      {}
     ]
    ],
+   "css/css-text/word-break/word-break-break-word-crash-001.html": [
+    [
+     "css/css-text/word-break/word-break-break-word-crash-001.html",
+     {}
+    ]
+   ],
    "css/css-transforms/2d-rotate-js.html": [
     [
      "css/css-transforms/2d-rotate-js.html",
@@ -231738,6 +231861,30 @@
      {}
     ]
    ],
+   "html/cross-origin/anonymous.tentative.html": [
+    [
+     "html/cross-origin/anonymous.tentative.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
+   "html/cross-origin/null.tentative.html": [
+    [
+     "html/cross-origin/null.tentative.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
+   "html/cross-origin/usecredentials.tentative.html": [
+    [
+     "html/cross-origin/usecredentials.tentative.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
    "html/dom/documents/dom-tree-accessors/Document.body.html": [
     [
      "html/dom/documents/dom-tree-accessors/Document.body.html",
@@ -244447,6 +244594,12 @@
      {}
     ]
    ],
+   "intersection-observer/root-margin-rounding.html": [
+    [
+     "intersection-observer/root-margin-rounding.html",
+     {}
+    ]
+   ],
    "intersection-observer/root-margin.html": [
     [
      "intersection-observer/root-margin.html",
@@ -245143,9 +245296,9 @@
      {}
     ]
    ],
-   "mathml/relations/css-styling/lengths-3.html": [
+   "mathml/relations/css-styling/lengths-2.html": [
     [
-     "mathml/relations/css-styling/lengths-3.html",
+     "mathml/relations/css-styling/lengths-2.html",
      {}
     ]
    ],
@@ -246006,6 +246159,12 @@
      {}
     ]
    ],
+   "mediacapture-streams/MediaStream-MediaElement-firstframe.https.html": [
+    [
+     "mediacapture-streams/MediaStream-MediaElement-firstframe.https.html",
+     {}
+    ]
+   ],
    "mediacapture-streams/MediaStream-MediaElement-srcObject.https.html": [
     [
      "mediacapture-streams/MediaStream-MediaElement-srcObject.https.html",
@@ -282003,6 +282162,43 @@
      {}
     ]
    ],
+   "timing-entrytypes-registry/registry.any.js": [
+    [
+     "timing-entrytypes-registry/registry.any.html",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "resources/utils.js"
+       ]
+      ]
+     }
+    ],
+    [
+     "timing-entrytypes-registry/registry.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "resources/utils.js"
+       ]
+      ]
+     }
+    ]
+   ],
+   "timing-entrytypes-registry/registry.window.js": [
+    [
+     "timing-entrytypes-registry/registry.window.html",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "resources/utils.js"
+       ]
+      ]
+     }
+    ]
+   ],
    "touch-events/historical.html": [
     [
      "touch-events/historical.html",
@@ -289485,6 +289681,14 @@
      {}
     ]
    ],
+   "webrtc/RTCPeerConnection-mandatory-getStats.https.html": [
+    [
+     "webrtc/RTCPeerConnection-mandatory-getStats.https.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
    "webrtc/RTCPeerConnection-ondatachannel.html": [
     [
      "webrtc/RTCPeerConnection-ondatachannel.html",
@@ -315130,19 +315334,19 @@
    "testharness"
   ],
   "beacon/headers/header-referrer-strict-origin-when-cross-origin.https.html": [
-   "ef6a5984066a81619b79b0416d70569881280884",
+   "f31003500941636eaef1c9a61ce38851c4cb1b23",
    "testharness"
   ],
   "beacon/headers/header-referrer-strict-origin.https.html": [
-   "ef6a5984066a81619b79b0416d70569881280884",
+   "b65bc795d2c82e8c2b3f29774d9f2c182da7c5c2",
    "testharness"
   ],
   "beacon/headers/header-referrer-unsafe-url.https.html": [
-   "9a3bccfbbffc6ea1753a8fde13a0045ed0209f73",
+   "26a062ebd85c221df40b6753d77dd33cd3776c11",
    "testharness"
   ],
   "beacon/headers/header-referrer.js": [
-   "026b091828c43aa53a0a6086faf082e25a1f9bd5",
+   "ebd67df1d767636a5044cec105ee5d3b1a3e606a",
    "support"
   ],
   "beacon/idlharness.any.js": [
@@ -340381,6 +340585,10 @@
    "41a334598f21ed9ac70a73c0307d7607039e5fe8",
    "testharness"
   ],
+  "css/css-backgrounds/parsing/border-color-computed.html": [
+   "9aee70b5bdfa842cfc6691dfa431c1bf041616c0",
+   "testharness"
+  ],
   "css/css-backgrounds/parsing/border-color-invalid.html": [
    "6e4d28e7983d62979f4dad843c007b964db00706",
    "testharness"
@@ -340393,6 +340601,10 @@
    "273fc0a7bf706151fcfe11199cbb7c5aff771100",
    "testharness"
   ],
+  "css/css-backgrounds/parsing/border-image-outset-computed.html": [
+   "dc259ce8d094da3c90767795c1df405831b8f837",
+   "testharness"
+  ],
   "css/css-backgrounds/parsing/border-image-outset-invalid.html": [
    "4102f603424d4673fe1432fcf7784fa285fbd9b9",
    "testharness"
@@ -340401,6 +340613,10 @@
    "ee85af87677f97d9e6263fade32e4beafe913009",
    "testharness"
   ],
+  "css/css-backgrounds/parsing/border-image-repeat-computed.html": [
+   "07aa949e972c96359d9d256bf04c469ae42c545f",
+   "testharness"
+  ],
   "css/css-backgrounds/parsing/border-image-repeat-invalid.html": [
    "de0998dcc5bf85a650560c8a97266159c2bffb26",
    "testharness"
@@ -340409,6 +340625,10 @@
    "f90ef71191e48ee399eac37cea9c356faaa486f5",
    "testharness"
   ],
+  "css/css-backgrounds/parsing/border-image-slice-computed.html": [
+   "9bc3801e4f59f028cc66f08cb473e9cc000a5586",
+   "testharness"
+  ],
   "css/css-backgrounds/parsing/border-image-slice-invalid.html": [
    "6b6e0e9d610bc6c1b76c9f31d4c1651a783399c9",
    "testharness"
@@ -340417,6 +340637,10 @@
    "671120b41b7e55bddd2c286dc7ce4807ce9c3665",
    "testharness"
   ],
+  "css/css-backgrounds/parsing/border-image-source-computed.html": [
+   "59cc2a7e14297a78eff04b553db58d157d07871d",
+   "testharness"
+  ],
   "css/css-backgrounds/parsing/border-image-source-invalid.html": [
    "8b1240a0d95296168cb1b7274a3ce3b8503a9341",
    "testharness"
@@ -340429,6 +340653,10 @@
    "67d22c18e2c6538a885b50ed6e65f56c1d146952",
    "testharness"
   ],
+  "css/css-backgrounds/parsing/border-image-width-computed.html": [
+   "62646921da7472eb3c68bfe2e401a66196ec3b7f",
+   "testharness"
+  ],
   "css/css-backgrounds/parsing/border-image-width-invalid.html": [
    "b3e9359749b00825c581040d06415d8f2efd7445",
    "testharness"
@@ -340453,6 +340681,10 @@
    "317803bf8819b2147390434e78d4efdcdc6d906b",
    "testharness"
   ],
+  "css/css-backgrounds/parsing/border-style-computed.html": [
+   "3e89f92dc40b9cc3147bb0a3f33ff3da480a6a5b",
+   "testharness"
+  ],
   "css/css-backgrounds/parsing/border-style-invalid.html": [
    "27fa45116fd150d69a77850f837ee43f7032c601",
    "testharness"
@@ -340465,6 +340697,10 @@
    "37b876ce4e97b2aa2ae08cb3447d42a658fcf56d",
    "testharness"
   ],
+  "css/css-backgrounds/parsing/border-width-computed.html": [
+   "9ca2484ca07c7bd4508d351feb3ec2ce9896b005",
+   "testharness"
+  ],
   "css/css-backgrounds/parsing/border-width-invalid.html": [
    "ec7eb72a9ac404a59390b9c89f7ae710f6620412",
    "testharness"
@@ -355294,11 +355530,11 @@
    "testharness"
   ],
   "css/css-grid/abspos/absolute-positioning-grid-container-containing-block-001.html": [
-   "e456af8ce0a30b430ab2696c892c6fde8884007c",
+   "4be43ddba2dec27a1dd2d1af95402e5158c7c9e6",
    "testharness"
   ],
   "css/css-grid/abspos/absolute-positioning-grid-container-parent-001.html": [
-   "a7a38ad0a0ab8c8fa13b7fac0a75268e1a026cbb",
+   "7025ccf55e9d70e5fa3db5159cd975e061003837",
    "testharness"
   ],
   "css/css-grid/abspos/descendant-static-position-001-ref.html": [
@@ -355350,7 +355586,7 @@
    "support"
   ],
   "css/css-grid/abspos/grid-positioned-children-writing-modes-001.html": [
-   "eb855279ca8b2be674180dd5240ed3860663ae45",
+   "d63b1894927bf12cec6b918b100d62ff8a7ed103",
    "reftest"
   ],
   "css/css-grid/abspos/grid-positioned-item-dynamic-change-001.html": [
@@ -355390,7 +355626,7 @@
    "support"
   ],
   "css/css-grid/abspos/grid-positioned-items-background-001.html": [
-   "19ee662e04e12e77ac0eec52b8da951ef1f27b5c",
+   "54146bce2581db8749ea75622edfdcd148d266bb",
    "reftest"
   ],
   "css/css-grid/abspos/grid-positioned-items-background-rtl-001-ref.html": [
@@ -355398,7 +355634,7 @@
    "support"
   ],
   "css/css-grid/abspos/grid-positioned-items-background-rtl-001.html": [
-   "9ed046b421533c12cf905dd175c682458279e10a",
+   "97ec1052f4be3ce0b26491c60d3c02184328dd12",
    "reftest"
   ],
   "css/css-grid/abspos/grid-positioned-items-content-alignment-001.html": [
@@ -355426,11 +355662,11 @@
    "testharness"
   ],
   "css/css-grid/abspos/grid-positioned-items-implicit-grid-001.html": [
-   "71f096aa74b9d9e012b115a21825843aa0d41e79",
+   "4b1a3d0f342f84b3a901513ce99bfcc96b635511",
    "testharness"
   ],
   "css/css-grid/abspos/grid-positioned-items-implicit-grid-line-001.html": [
-   "7b8fa4ef7bd632fcbcfae5084cb41e8424f4363f",
+   "8fc8918ee68b215da3e93fb73282ab8e0b2ef287",
    "testharness"
   ],
   "css/css-grid/abspos/grid-positioned-items-padding-001.html": [
@@ -355438,7 +355674,7 @@
    "testharness"
   ],
   "css/css-grid/abspos/grid-positioned-items-unknown-named-grid-line-001.html": [
-   "6e61f7c2de36a1d799aba0de6d10c52147d406d6",
+   "663dab45b3dbe76075c6a32a3e7b0b6a59213181",
    "testharness"
   ],
   "css/css-grid/abspos/grid-positioned-items-within-grid-implicit-track-001.html": [
@@ -355446,7 +355682,7 @@
    "testharness"
   ],
   "css/css-grid/abspos/grid-sizing-positioned-items-001.html": [
-   "0e8cd3369f7f154725f746ce4725940bec746582",
+   "e74b2b96fe62e102f4313c00bcc730bec76a667a",
    "testharness"
   ],
   "css/css-grid/abspos/orthogonal-positioned-grid-descendants-001-expected.txt": [
@@ -355846,11 +356082,11 @@
    "reftest"
   ],
   "css/css-grid/abspos/positioned-grid-items-should-not-create-implicit-tracks-001.html": [
-   "5ef006ae137c5604e9b53e322aeec60bf4841e55",
+   "adb4a7acf27514550682429e998feadb2af5676d",
    "testharness"
   ],
   "css/css-grid/abspos/positioned-grid-items-should-not-take-up-space-001.html": [
-   "597e778019b6276cdfd01676f2abf6f521faff29",
+   "50f9984370baa88d2940b5457b54067a9497a812",
    "testharness"
   ],
   "css/css-grid/abspos/positioned-grid-items-sizing-001-ref.html": [
@@ -361629,6 +361865,14 @@
    "49b8f918585b46afa8687e7e75979062f49c3e2a",
    "reftest"
   ],
+  "css/css-multicol/multicol-span-all-011-ref.html": [
+   "54981d81068873d95a0b3725fc8aabdb542ef491",
+   "support"
+  ],
+  "css/css-multicol/multicol-span-all-011.html": [
+   "869a889fcb4eee69e05797d1824e5ae8e2b6c00f",
+   "reftest"
+  ],
   "css/css-multicol/multicol-span-all-block-sibling-003.xht": [
    "abaa45f0a85023f3f07a9db483629b74d2b09d71",
    "reftest"
@@ -363633,6 +363877,10 @@
    "2b158a86f6599e43f6a2315a2943b4d394405ba5",
    "testharness"
   ],
+  "css/css-position/position-absolute-chrome-bug-001.html": [
+   "3e8899a94099983b147f0877a6d45a17341a0364",
+   "testharness"
+  ],
   "css/css-position/position-absolute-container-dynamic-002.html": [
    "91d862835e6d1351deefb26f7e2b71a9539bbd6c",
    "testharness"
@@ -375109,6 +375357,10 @@
    "bc5a08d38a505b1b08f204e6d243b43fa3dd34bc",
    "reftest"
   ],
+  "css/css-text/word-break/word-break-break-word-crash-001.html": [
+   "894a6f3aa0ce257a92926158b75a29986a98e079",
+   "testharness"
+  ],
   "css/css-text/word-break/word-break-break-word-overflow-wrap-interactions-ref.html": [
    "3c6ab3863f88646f2fe9132963704c72d6b8d3d7",
    "support"
@@ -403757,10 +404009,6 @@
    "9dccd4ca24df3c2cae5fef4ee209ab195546192f",
    "testharness"
   ],
-  "custom-elements/upgrading-expected.txt": [
-   "592b7f45e37b5b236ec9aa2015601e39cf7b0640",
-   "support"
-  ],
   "custom-elements/upgrading.html": [
    "d6b8ed387540ae9572774e5557b1168f844a017f",
    "testharness"
@@ -416149,6 +416397,70 @@
    "34bd099a302f893f92586241ea38aac812bf28d0",
    "support"
   ],
+  "html/cross-origin/anonymous.tentative.html": [
+   "ef9b9bb7b878a738c8f7e377d4cfe62b41dfea7f",
+   "testharness"
+  ],
+  "html/cross-origin/anonymous.tentative.html.headers": [
+   "a76b601291ec4323da4469a0e09d62c84f81efc3",
+   "support"
+  ],
+  "html/cross-origin/null.tentative.html": [
+   "ae871c4a273533eaae2e4dbfb2f0dd71f4ea34d0",
+   "testharness"
+  ],
+  "html/cross-origin/null.tentative.html.headers": [
+   "fd34f127d558b1288829b8e15f35bcc01c54749e",
+   "support"
+  ],
+  "html/cross-origin/resources/navigate_anonymous.sub.html": [
+   "d4b38bc1a10003f8adc0e62224c5d3378638fb4f",
+   "support"
+  ],
+  "html/cross-origin/resources/navigate_anonymous.sub.html.headers": [
+   "a76b601291ec4323da4469a0e09d62c84f81efc3",
+   "support"
+  ],
+  "html/cross-origin/resources/navigate_null.sub.html": [
+   "1008f70ff123ae5e507a95ac4f16d32bbb74c983",
+   "support"
+  ],
+  "html/cross-origin/resources/navigate_usecredentials.sub.html": [
+   "1008f70ff123ae5e507a95ac4f16d32bbb74c983",
+   "support"
+  ],
+  "html/cross-origin/resources/navigate_usecredentials.sub.html.headers": [
+   "a84d3782037e7a0573f3b621941e293560792628",
+   "support"
+  ],
+  "html/cross-origin/resources/nothing.txt": [
+   "9dafe9be2099a3b02b618c673bcf865a1ffb4f9d",
+   "support"
+  ],
+  "html/cross-origin/resources/nothing.txt.headers": [
+   "cb762eff806849df46dc758ef7b98b63f27f54c9",
+   "support"
+  ],
+  "html/cross-origin/resources/popup_and_close.sub.html": [
+   "2489fa8d2470df6930601c79fc1a9c1575733524",
+   "support"
+  ],
+  "html/cross-origin/resources/popup_and_close.sub.html.headers": [
+   "a76b601291ec4323da4469a0e09d62c84f81efc3",
+   "support"
+  ],
+  "html/cross-origin/usecredentials.tentative-expected.txt": [
+   "f65e0267dcb537790843cbf969e04002fdafe23d",
+   "support"
+  ],
+  "html/cross-origin/usecredentials.tentative.html": [
+   "55c0f2235db27ad119d652782141de68f5de62a6",
+   "testharness"
+  ],
+  "html/cross-origin/usecredentials.tentative.html.headers": [
+   "a84d3782037e7a0573f3b621941e293560792628",
+   "support"
+  ],
   "html/dom/documents/dom-tree-accessors/Document.body.html": [
    "f42125029568476b4076603a1b982a4989b65d35",
    "testharness"
@@ -434362,7 +434674,7 @@
    "support"
   ],
   "interfaces/page-visibility.idl": [
-   "28fda2cbc251347ba5fddb27cb11aa555d55aa64",
+   "6b8bd52a047ce411b968a79e6d0f7d152ab32a57",
    "support"
   ],
   "interfaces/paint-timing.idl": [
@@ -434382,7 +434694,7 @@
    "support"
   ],
   "interfaces/performance-timeline.idl": [
-   "51752b139589e64088364109d8c5e117c7811e95",
+   "8ded59d8a269f83037a8845417c1275dd91ec538",
    "support"
   ],
   "interfaces/permissions.idl": [
@@ -434530,7 +434842,7 @@
    "support"
   ],
   "interfaces/web-nfc.idl": [
-   "a5709161bdb45f7a02bdd9b78f73febd8d21e222",
+   "26f32a04ac981db772d26f34cbe3a40cdc78a83f",
    "support"
   ],
   "interfaces/web-share.idl": [
@@ -434729,6 +435041,10 @@
    "295bbf047e6523313ce74f2e383ed769c0d5c81b",
    "support"
   ],
+  "intersection-observer/root-margin-rounding.html": [
+   "f5e33230199eb77a16f8fe99eeb1c9c1618c3e19",
+   "testharness"
+  ],
   "intersection-observer/root-margin.html": [
    "898454c4f385794d78ef4635612b6754cdd060af",
    "testharness"
@@ -435046,7 +435362,7 @@
    "testharness"
   ],
   "lint.whitelist": [
-   "f17a929f9a46757eceabbd468e9df9857b2f10b4",
+   "be52aa67c00b9484180e316d6594e31d4918087d",
    "support"
   ],
   "loading/preloader-css-import-no-quote.tentative.html": [
@@ -435537,15 +435853,7 @@
    "30916d5a567a882eb9b0fb7c6a07b7c2e02416f2",
    "reftest"
   ],
-  "mathml/relations/css-styling/lengths-2-ref.html": [
-   "9fca6f49632ca080ee1b2a32a9ce2d251241dfcc",
-   "support"
-  ],
   "mathml/relations/css-styling/lengths-2.html": [
-   "37cc640b30783ad717d7eef8551b47754f7c9986",
-   "reftest"
-  ],
-  "mathml/relations/css-styling/lengths-3.html": [
    "aa38e9729de8569151b98307395ec8a2a5fe4b7f",
    "testharness"
   ],
@@ -436869,6 +437177,14 @@
    "f1e2d5600f25c3674e4233ba15046ad634bd46c6",
    "testharness"
   ],
+  "mediacapture-streams/MediaStream-MediaElement-firstframe.https-expected.txt": [
+   "8b4583f6db0bab3072fbf877517066d5ef201caf",
+   "support"
+  ],
+  "mediacapture-streams/MediaStream-MediaElement-firstframe.https.html": [
+   "1c6292458865bdeb3cfb5a64a7d4e4c9c215c866",
+   "testharness"
+  ],
   "mediacapture-streams/MediaStream-MediaElement-preload-none-manual.https.html": [
    "758a273bb192bea67776d432125d548bfebd5ff8",
    "manual"
@@ -436878,7 +437194,7 @@
    "support"
   ],
   "mediacapture-streams/MediaStream-MediaElement-srcObject.https.html": [
-   "4b9a3c8246d04aafff5877fc78001a5f9d00f82d",
+   "3b16006e0f52ca966c0298bef59a10a19e4038a3",
    "testharness"
   ],
   "mediacapture-streams/MediaStream-add-audio-track.https.html": [
@@ -466801,6 +467117,14 @@
    "bb7c8206a116af9e7b242c4e9546d570cea6afd8",
    "reftest"
   ],
+  "svg/text/reftests/text-xml-space-001-ref.svg": [
+   "1572149cf68bde8c0e8c032b28d37ae95c64652a",
+   "support"
+  ],
+  "svg/text/reftests/text-xml-space-001.svg": [
+   "c58bd9d4e57cbe6891191aa8c67844cb63f73347",
+   "reftest"
+  ],
   "svg/text/reftests/textpath-shape-001-ref.svg": [
    "10827c85810cdf9dc7e70a665c289814d35ed219",
    "support"
@@ -467029,6 +467353,22 @@
    "3cf888b7dbaeb370ef1b34409540337dee2c8e33",
    "support"
   ],
+  "timing-entrytypes-registry/META.yml": [
+   "c09a6e03fd19f5a405b391c2c4671df6ff04edf1",
+   "support"
+  ],
+  "timing-entrytypes-registry/registry.any.js": [
+   "4db249b16bea55e678f62721ee1002b012fc0bbf",
+   "testharness"
+  ],
+  "timing-entrytypes-registry/registry.window.js": [
+   "21ef2230e9ebea5b853e243c51905b92098fcd95",
+   "testharness"
+  ],
+  "timing-entrytypes-registry/resources/utils.js": [
+   "0ec96057ad80928be183530e66f638b47e7d4c01",
+   "support"
+  ],
   "tools/META.yml": [
    "7cc22a28c20c01f2c602b6b79814fc6844054306",
    "support"
@@ -474698,7 +475038,7 @@
    "support"
   ],
   "web-nfc/idlharness.https.window-expected.txt": [
-   "4b697a3da45b1236c0737e42bcaf092adb00dd7e",
+   "da18d84cd0b173a92271bcafd696454ab678a862",
    "support"
   ],
   "web-nfc/idlharness.https.window.js": [
@@ -477690,7 +478030,7 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-helper.js": [
-   "d859ac736ae6bf0187640dbe2148d8e0d64d9345",
+   "6a4ce854db70573a368ced9889e0623b15311f72",
    "support"
   ],
   "webrtc/RTCPeerConnection-iceConnectionState-disconnected.https.html": [
@@ -477702,7 +478042,7 @@
    "support"
   ],
   "webrtc/RTCPeerConnection-iceConnectionState.https.html": [
-   "6d4ab50b0e266c30d6ce329e1f587886f33ae5fb",
+   "385bb51719e6ee5049f700f783d0faa6753cdff7",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-iceGatheringState-expected.txt": [
@@ -477713,6 +478053,14 @@
    "e170e4a2f87fc4c3260a7acd323a98e1adfa3726",
    "testharness"
   ],
+  "webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt": [
+   "9d294da84dc91544a6369bf66bfc70324d7d61a6",
+   "support"
+  ],
+  "webrtc/RTCPeerConnection-mandatory-getStats.https.html": [
+   "fd8c74b918440b72faaa570753a9a6dc88e85dcc",
+   "testharness"
+  ],
   "webrtc/RTCPeerConnection-ondatachannel-expected.txt": [
    "d04de3ba27102ce318f9cd68e1cb91b1b76da7b6",
    "support"
@@ -478098,7 +478446,7 @@
    "support"
   ],
   "webrtc/protocol/candidate-exchange.https.html": [
-   "2603a02cddf3f026b09b8a233d17ff3f92bd43a1",
+   "d1bc35819cee8e13485765e6f70836521dc5e7e7",
    "testharness"
   ],
   "webrtc/protocol/dtls-fingerprint-validation.html": [
@@ -480626,11 +480974,11 @@
    "reftest"
   ],
   "webvtt/rendering/cues-with-video/processing-model/basic-ref.html": [
-   "89d7f35ef1f8a405f7fe8d307dd1c69e24866740",
+   "182bc69277be6e553873d115f3af1f4550090986",
    "support"
   ],
   "webvtt/rendering/cues-with-video/processing-model/basic.html": [
-   "983600bdf1889e15cc4341a348e15201a07055d3",
+   "ca77eb734bfa1f819c0a76b519946cf9af0488f7",
    "reftest"
   ],
   "webvtt/rendering/cues-with-video/processing-model/bidi/bidi_ruby-ref.html": [
@@ -480882,11 +481230,11 @@
    "reftest"
   ],
   "webvtt/rendering/cues-with-video/processing-model/line_0_is_top-ref.html": [
-   "7edb8876e0ec3cc63fa63eac6d99a01bf4f075f8",
+   "85f2a95fa8a263bbe9bad330db7470142fb8e6b5",
    "support"
   ],
   "webvtt/rendering/cues-with-video/processing-model/line_0_is_top.html": [
-   "2167f218f366dbd2ec008d2d5d49c59f75ace678",
+   "c780a223e73482adc68ba8d0dd664ff5972e5932",
    "reftest"
   ],
   "webvtt/rendering/cues-with-video/processing-model/line_1_wrapped_cue_grow_downwards-ref.html": [
@@ -481558,11 +481906,11 @@
    "reftest"
   ],
   "webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_namespace-ref.html": [
-   "3aea69adc46fd7914307791260245cb3107f6da7",
+   "13705162368153d4950a83e5c881fc843ae5860b",
    "support"
   ],
   "webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_namespace.html": [
-   "777ce661c2e8c3d82626914ec354c565480b6bf5",
+   "3989f2180a0462a0951dc949fb51c4e67872e0be",
    "reftest"
   ],
   "webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_outline_properties-ref.html": [
@@ -483018,7 +483366,7 @@
    "testharness"
   ],
   "workers/Worker-nested-importScripts-error.html": [
-   "8863b7523010dd8566d1ed42094e519efc500a65",
+   "bd96c835df9275e6f191adfe79f47f1df2d7d5bf",
    "testharness"
   ],
   "workers/Worker-replace-event-handler.any.js": [
diff --git a/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer-strict-origin-when-cross-origin.https.html b/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer-strict-origin-when-cross-origin.https.html
index ef6a598..f310035 100644
--- a/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer-strict-origin-when-cross-origin.https.html
+++ b/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer-strict-origin-when-cross-origin.https.html
@@ -12,10 +12,10 @@
     <script src="/common/get-host-info.sub.js"></script>
     <script src="/beacon/headers/header-referrer.js"></script>
     <script>
-      var testBase = get_host_info().HTTPS_ORIGIN +  RESOURCES_DIR;
+      var testBase = get_host_info().HTTPS_REMOTE_ORIGIN +  RESOURCES_DIR;
       testReferrerHeader(testBase, referrerOrigin);
-      testBase = get_host_info().HTTP_ORIGIN + RESOURCES_DIR;
-      testReferrerHeader(testBase, "");
+      testBase = get_host_info().HTTP_REMOTE_ORIGIN + RESOURCES_DIR;
+      testReferrerHeader(testBase, "", true);
     </script>
   </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer-strict-origin.https.html b/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer-strict-origin.https.html
index ef6a598..b65bc795 100644
--- a/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer-strict-origin.https.html
+++ b/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer-strict-origin.https.html
@@ -15,7 +15,7 @@
       var testBase = get_host_info().HTTPS_ORIGIN +  RESOURCES_DIR;
       testReferrerHeader(testBase, referrerOrigin);
       testBase = get_host_info().HTTP_ORIGIN + RESOURCES_DIR;
-      testReferrerHeader(testBase, "");
+      testReferrerHeader(testBase, "", true);
     </script>
   </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer-unsafe-url.https.html b/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer-unsafe-url.https.html
index 9a3bccf..26a062e 100644
--- a/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer-unsafe-url.https.html
+++ b/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer-unsafe-url.https.html
@@ -12,8 +12,10 @@
     <script src="/common/get-host-info.sub.js"></script>
     <script src="/beacon/headers/header-referrer.js"></script>
     <script>
-      var testBase = get_host_info().HTTP_ORIGIN + RESOURCES_DIR;
+      var testBase = get_host_info().HTTPS_ORIGIN +  RESOURCES_DIR;
       testReferrerHeader(testBase, referrerUrl);
+      testBase = get_host_info().HTTP_ORIGIN + RESOURCES_DIR;
+      testReferrerHeader(testBase, referrerUrl, true);
     </script>
   </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer.js b/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer.js
index 026b091..ebd67df 100644
--- a/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer.js
+++ b/third_party/blink/web_tests/external/wpt/beacon/headers/header-referrer.js
@@ -3,12 +3,15 @@
 var referrerOrigin = self.location.origin + '/';
 var referrerUrl = self.location.href;
 
-function testReferrerHeader(testBase, expectedReferrer) {
+function testReferrerHeader(testBase, expectedReferrer, mayBeBlockedAsMixedContent = false) {
   var id = self.token();
   var testUrl = testBase + "inspect-header.py?header=referer&cmd=put&id=" + id;
 
   promise_test(function(test) {
-    assert_true(navigator.sendBeacon(testUrl), "SendBeacon Succeeded");
+    const sentBeacon = navigator.sendBeacon(testUrl);
+    if (mayBeBlockedAsMixedContent && !sentBeacon)
+      return Promise.resolve();
+    assert_true(sentBeacon, "SendBeacon Succeeded");
     return pollResult(expectedReferrer, id) .then(result => {
       assert_equals(result, expectedReferrer, "Correct referrer header result");
     });
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-color-computed.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-color-computed.html
new file mode 100644
index 0000000..9aee70b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-color-computed.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders: getComputedValue().borderColor</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#border-color">
+<meta name="assert" content="border-color computed value is the computed colors.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #target {
+    color: lime;
+  }
+</style>
+</head>
+<body>
+<div id="target"></div>
+<script>
+'use strict';
+const currentColor = "rgb(0, 255, 0)";
+const red = "rgb(255, 0, 0)";
+const yellow = "rgb(255, 255, 0)";
+const green = "rgb(0, 128, 0)";
+const blue = "rgb(0, 0, 255)";
+
+test_computed_value("border-color", "currentcolor", currentColor);
+test_computed_value("border-color", "red yellow", red + " " + yellow);
+test_computed_value("border-color", "red yellow currentcolor", red + " " + yellow + " " + currentColor);
+test_computed_value("border-color", "red yellow green blue", red + " " + yellow + " " + green + " " + blue);
+
+test_computed_value("border-top-color", "red", red);
+test_computed_value("border-right-color", "yellow", yellow);
+test_computed_value("border-bottom-color", "green", green);
+test_computed_value("border-left-color", "blue", blue);
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-outset-computed.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-outset-computed.html
new file mode 100644
index 0000000..dc259ce8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-outset-computed.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders: getComputedValue().borderImageOutset</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#border-image-outset">
+<meta name="assert" content="border-image-outset computed value is four values, each a number or absolute length.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #target {
+    font-size: 40px;
+  }
+</style>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("border-image-outset", "1px");
+test_computed_value("border-image-outset", "1px 2");
+test_computed_value("border-image-outset", "1px 2 3px");
+test_computed_value("border-image-outset", "1px 2 3px 4");
+test_computed_value("border-image-outset", "0 calc(0.5em + 10px) 3 calc(-0.5em + 10px)", "0 30px 3 0px");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-repeat-computed.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-repeat-computed.html
new file mode 100644
index 0000000..07aa949
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-repeat-computed.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders: getComputedValue().borderImageRepeat</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#border-image-repeat">
+<meta name="assert" content="border-image-repeat computed value is specified keywords.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("border-image-repeat", "round");
+test_computed_value("border-image-repeat", "stretch repeat");
+test_computed_value("border-image-repeat", "round space");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-slice-computed.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-slice-computed.html
new file mode 100644
index 0000000..9bc3801e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-slice-computed.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders: getComputedValue().borderImageSlice</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#border-image-slice">
+<meta name="assert" content="border-image-slice computed value is four values, each either a number or percentage; plus a fill keyword if specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("border-image-slice", "1");
+test_computed_value("border-image-slice", "1 2%");
+test_computed_value("border-image-slice", "1 2% 3");
+test_computed_value("border-image-slice", "1 2% 3 4%");
+
+test_computed_value("border-image-slice", "1% 2 3% 4 fill");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-source-computed.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-source-computed.html
new file mode 100644
index 0000000..59cc2a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-source-computed.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders: getComputedValue().borderImageSource</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#border-image-source">
+<meta name="assert" content="border-image-source computed value is the keyword none or the specified image with URIs made absolute.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("border-image-source", "none");
+test_computed_value("border-image-source", 'url("http://www.example.com/")');
+
+test(() => {
+  const target = document.getElementById('target');
+  target.style['border-image-source'] = 'url("a.b#c")';
+  const result = getComputedStyle(target)['border-image-source'];
+  const resolved = new URL("a.b#c", document.URL).href;
+  assert_equals(result, 'url("' + resolved + '")');
+}, 'url values are made absolute');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-width-computed.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-width-computed.html
new file mode 100644
index 0000000..6264692
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-width-computed.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders: getComputedValue().borderImageWidth</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#border-image-width">
+<meta name="assert" content="border-image-width computed value is four values, each either a number, the keyword auto, or a computed length-percentage value.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #target {
+    font-size: 40px;
+  }
+</style>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("border-image-width", "1");
+test_computed_value("border-image-width", "auto");
+test_computed_value("border-image-width", "10px");
+test_computed_value("border-image-width", "20%");
+test_computed_value("border-image-width", "calc(20% + 10px)");
+test_computed_value("border-image-width", "calc(-0.5em + 10px)", "0px");
+test_computed_value("border-image-width", "calc(0.5em + 10px)", "30px");
+test_computed_value("border-image-width", "1 auto");
+test_computed_value("border-image-width", "1 auto 10px");
+test_computed_value("border-image-width", "1 auto 10px 20%");
+test_computed_value("border-image-width", "20% 10px auto 1");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-style-computed.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-style-computed.html
new file mode 100644
index 0000000..3e89f92d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-style-computed.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders: getComputedValue().borderStyle</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#border-style">
+<meta name="assert" content="border-style computed value is the specified keywords.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("border-style", "none");
+test_computed_value("border-style", "inset outset");
+test_computed_value("border-style", "hidden dotted dashed");
+test_computed_value("border-style", "solid double groove ridge");
+
+test_computed_value("border-top-style", "solid");
+test_computed_value("border-right-style", "double");
+test_computed_value("border-bottom-style", "groove");
+test_computed_value("border-left-style", "ridge");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-width-computed.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-width-computed.html
new file mode 100644
index 0000000..9ca2484
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-width-computed.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders: getComputedValue().borderWidth</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#border-width">
+<meta name="assert" content="border-width computed value is the absolute length; zero if the border style is none or hidden.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #box {
+    border-style: dotted; /* Avoid border-*-width computed style 0 */
+    border-top-width: thin;
+    border-right-width: medium;
+    border-bottom-width: thick;
+  }
+  #target {
+    border-style: dotted; /* Avoid border-*-width computed style 0 */
+    font-size: 40px;
+  }
+</style>
+</head>
+<body>
+<div id="box"></div>
+<div id="target"></div>
+<script>
+'use strict';
+const box = document.getElementById('box');
+const thinWidth = getComputedStyle(box).borderTopWidth;
+const mediumWidth = getComputedStyle(box).borderRightWidth;
+const thickWidth = getComputedStyle(box).borderBottomWidth;
+
+test_computed_value("border-width", "1px");
+test_computed_value("border-width", "1px 2px");
+test_computed_value("border-width", "1px 2px 3px");
+test_computed_value("border-width", "1px 2px 3px 4px");
+
+test_computed_value("border-width", "0.5em", "20px");
+test_computed_value("border-width", "2px thin medium thick", "2px " + thinWidth + " " + mediumWidth + " " + thickWidth);
+
+test_computed_value("border-top-width", "0px");
+test_computed_value("border-right-width", "10px");
+test_computed_value("border-bottom-width", "calc(-0.5em + 10px)", "0px");
+test_computed_value("border-left-width", "calc(0.5em + 10px)", "30px");
+
+test(() => {
+  const thin = Number(thinWidth.replace("px", ""));
+  const medium = Number(mediumWidth.replace("px", ""));
+  const thick = Number(thickWidth.replace("px", ""));
+  assert_less_than_equal(0, thin);
+  assert_less_than_equal(thin, medium);
+  assert_less_than_equal(medium, thick);
+}, "thin ≤ medium ≤ thick");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/absolute-positioning-grid-container-containing-block-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/absolute-positioning-grid-container-containing-block-001.html
index e456af8..4be43ddb 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/absolute-positioning-grid-container-containing-block-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/absolute-positioning-grid-container-containing-block-001.html
@@ -4,6 +4,7 @@
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="9. Absolute Positioning">
 <meta name="assert" content="This test checks the behavior of the absolutely positioned elements with a grid container as containing block.">
+<link rel="stylesheet" href="/fonts/ahem.css">
 <link rel="stylesheet" href="support/grid.css">
 <style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/absolute-positioning-grid-container-parent-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/absolute-positioning-grid-container-parent-001.html
index a7a38ad0..7025ccf 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/absolute-positioning-grid-container-parent-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/absolute-positioning-grid-container-parent-001.html
@@ -4,6 +4,7 @@
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="9. Absolute Positioning">
 <meta name="assert" content="This test checks the behavior of the absolutely positioned elements with a grid container as parent.">
+<link rel="stylesheet" href="/fonts/ahem.css">
 <link rel="stylesheet" href="support/grid.css">
 <style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-children-writing-modes-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-children-writing-modes-001.html
index eb85527..d63b189 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-children-writing-modes-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-children-writing-modes-001.html
@@ -5,6 +5,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="9. Absolute Positioning">
 <link rel="match" href="grid-positioned-children-writing-modes-001-ref.html">
 <meta name="assert" content="This test checks the behavior of the positioned grid children in combination with the writing modes and text direction properties.">
+<link rel="stylesheet" href="/fonts/ahem.css">
 <link rel="stylesheet" href="support/grid.css">
 <style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-background-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-background-001.html
index 19ee662e..54146bc 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-background-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-background-001.html
@@ -5,6 +5,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="9. Absolute Positioning">
 <link rel="match" href="grid-positioned-items-background-001-ref.html">
 <meta name="assert" content="This test checks that the background of positioned items is painted in the right position">
+<link rel="stylesheet" href="/fonts/ahem.css">
 <link rel="stylesheet" href="support/grid.css">
 <style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-background-rtl-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-background-rtl-001.html
index 9ed046b..97ec105 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-background-rtl-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-background-rtl-001.html
@@ -5,6 +5,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="9. Absolute Positioning">
 <link rel="match" href="grid-positioned-items-background-rtl-001-ref.html">
 <meta name="assert" content="This test checks that the background of positioned items is painted in the right position using RTL direction.">
+<link rel="stylesheet" href="/fonts/ahem.css">
 <link rel="stylesheet" href="support/grid.css">
 <style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-implicit-grid-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-implicit-grid-001.html
index 71f096a..4b1a3d0f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-implicit-grid-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-implicit-grid-001.html
@@ -5,6 +5,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="9. Absolute Positioning">
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#implicit-grids" title="7.5. The Implicit Grid">
 <meta name="assert" content="This test checks the behavior of the absolutely positioned grid items placed on the implicit grid.">
+<link rel="stylesheet" href="/fonts/ahem.css">
 <link rel="stylesheet" href="support/grid.css">
 <style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-implicit-grid-line-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-implicit-grid-line-001.html
index 7b8fa4e..8fc8918 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-implicit-grid-line-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-implicit-grid-line-001.html
@@ -5,6 +5,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="9. Absolute Positioning">
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#implicit-grids" title="7.5. The Implicit Grid">
 <meta name="assert" content="This test checks that grid placement properties of absolutely positioned items using implicit grid lines are treated as 'auto'.">
+<link rel="stylesheet" href="/fonts/ahem.css">
 <link rel="stylesheet" href="support/grid.css">
 <style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-unknown-named-grid-line-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-unknown-named-grid-line-001.html
index 6e61f7c..663dab45 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-unknown-named-grid-line-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-positioned-items-unknown-named-grid-line-001.html
@@ -4,6 +4,7 @@
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="9. Absolute Positioning">
 <meta name="assert" content="This test checks that grid placement properties of absolutely positioned items can reference implicit grid lines.">
+<link rel="stylesheet" href="/fonts/ahem.css">
 <link rel="stylesheet" href="support/grid.css">
 <style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-sizing-positioned-items-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-sizing-positioned-items-001.html
index 0e8cd33..e74b2b9 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-sizing-positioned-items-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/grid-sizing-positioned-items-001.html
@@ -4,6 +4,7 @@
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="9. Absolute Positioning">
 <meta name="assert" content="This test checks the different size options for absolutely positioned grid items.">
+<link rel="stylesheet" href="/fonts/ahem.css">
 <link href="support/grid.css" rel="stylesheet">
 <style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/positioned-grid-items-should-not-create-implicit-tracks-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/positioned-grid-items-should-not-create-implicit-tracks-001.html
index 5ef006ae..adb4a7a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/positioned-grid-items-should-not-create-implicit-tracks-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/positioned-grid-items-should-not-create-implicit-tracks-001.html
@@ -4,6 +4,7 @@
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="9. Absolute Positioning">
 <meta name="assert" content="This test checks that positioned items shouldn't create implicit tracks on the grid.">
+<link rel="stylesheet" href="/fonts/ahem.css">
 <link href="support/grid.css" rel="stylesheet">
 <style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/positioned-grid-items-should-not-take-up-space-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/positioned-grid-items-should-not-take-up-space-001.html
index 597e7780..50f9984 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/positioned-grid-items-should-not-take-up-space-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/positioned-grid-items-should-not-take-up-space-001.html
@@ -4,6 +4,7 @@
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos" title="9. Absolute Positioning">
 <meta name="assert" content="This test checks that positioned items shouldn't take up space or otherwise participate in the layout of the grid.">
+<link rel="stylesheet" href="/fonts/ahem.css">
 <link href="support/grid.css" rel="stylesheet">
 <style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-011-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-011-ref.html
new file mode 100644
index 0000000..54981d81
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-011-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test Reference: Test a bidi-override multi-column container with a dir=rtl column-span:all child</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+
+  <style>
+  article {
+    column-count: 1;
+    column-rule: 6px solid;
+    width: 400px;
+    outline: 1px solid black;
+  }
+  h3 {
+    /* "column-count: 1" makes this behave like a real spanner. */
+    outline: 1px solid blue;
+  }
+  </style>
+
+  <article>
+    <div>before</div><h3 dir="rtl">spanner</h3><div>after</div>
+  </article>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-011.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-011.html
new file mode 100644
index 0000000..869a889
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-011.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Test a bidi-override multi-column container with a dir=rtl column-span:all child</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
+  <link rel="match" href="multicol-span-all-011-ref.html">
+  <meta name="assert" content="This test checks that the text is correctly split by 'dir=rtl' column-span:all child in a bidi-override multi-column container.">
+
+  <style>
+  article {
+    column-count: 2;
+    column-rule: 6px solid;
+    width: 400px;
+    outline: 1px solid black;
+    unicode-bidi: bidi-override; /* Needed to trigger bidi resolution. */
+  }
+  h3 {
+    column-span: all;
+    outline: 1px solid blue;
+  }
+  </style>
+
+  <article>
+    <div>before<h3 dir="rtl">spanner</h3>after</div>
+  </article>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/upgrading-expected.txt b/third_party/blink/web_tests/external/wpt/custom-elements/upgrading-expected.txt
deleted file mode 100644
index 592b7f45..0000000
--- a/third_party/blink/web_tests/external/wpt/custom-elements/upgrading-expected.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-This is a testharness.js-based test.
-PASS Creating an element in the document of the template elements must not enqueue a custom element upgrade reaction because the document does not have a browsing context
-PASS Creating an element in the document of the template elements and inserting into the document must not enqueue a custom element upgrade reaction
-PASS Creating an element in the document of the template elements and adopting back to a document with browsing context must enqueue a custom element upgrade reaction
-PASS Creating an element in a new document must not enqueue a custom element upgrade reaction because the document does not have a browsing context
-PASS Creating an element in a new document and inserting into the document must not enqueue a custom element upgrade reaction
-PASS Creating an element in a new document and adopting back to a document with browsing context must enqueue a custom element upgrade reaction
-PASS Creating an element in a cloned document must not enqueue a custom element upgrade reaction because the document does not have a browsing context
-PASS Creating an element in a cloned document and inserting into the document must not enqueue a custom element upgrade reaction
-PASS Creating an element in a cloned document and adopting back to a document with browsing context must enqueue a custom element upgrade reaction
-PASS Creating an element in a document created by createHTMLDocument must not enqueue a custom element upgrade reaction because the document does not have a browsing context
-PASS Creating an element in a document created by createHTMLDocument and inserting into the document must not enqueue a custom element upgrade reaction
-PASS Creating an element in a document created by createHTMLDocument and adopting back to a document with browsing context must enqueue a custom element upgrade reaction
-PASS Creating an element in an HTML document created by createDocument must not enqueue a custom element upgrade reaction because the document does not have a browsing context
-PASS Creating an element in an HTML document created by createDocument and inserting into the document must not enqueue a custom element upgrade reaction
-PASS Creating an element in an HTML document created by createDocument and adopting back to a document with browsing context must enqueue a custom element upgrade reaction
-PASS Creating an element in an HTML document fetched by XHR must not enqueue a custom element upgrade reaction because the document does not have a browsing context
-PASS Creating an element in an HTML document fetched by XHR and inserting into the document must not enqueue a custom element upgrade reaction
-PASS Creating an element in an HTML document fetched by XHR and adopting back to a document with browsing context must enqueue a custom element upgrade reaction
-PASS Creating an element in the document of an iframe must not enqueue a custom element upgrade reaction if there is no matching definition
-PASS Creating an element in the document of an iframe must enqueue a custom element upgrade reaction if there is a matching definition
-PASS "define" in the document of an iframe must not enqueue a custom element upgrade reaction on a disconnected unresolved custom element
-PASS Inserting an unresolved custom element into the document of an iframe must enqueue a custom element upgrade reaction
-PASS "define" in the document of an iframe must enqueue a custom element upgrade reaction on a connected unresolved custom element
-PASS Adopting (and leaving disconnceted) an unresolved custom element into the document of an iframe must not enqueue a custom element upgrade reaction
-PASS Adopting and inserting an unresolved custom element into the document of an iframe must enqueue a custom element upgrade reaction
-FAIL If definition's disable shadow is true and element's shadow root is non-null, then throw a "NotSupportedError" DOMException. assert_false: Upgrading should fail. expected false got true
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/anonymous.tentative.html b/third_party/blink/web_tests/external/wpt/html/cross-origin/anonymous.tentative.html
new file mode 100644
index 0000000..ef9b9bb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/anonymous.tentative.html
@@ -0,0 +1,219 @@
+<!doctype html>
+<meta name="timeout" content="long">
+<title>Cross-Origin header and nested navigable resource without such header</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/get-host-info.sub.js"></script>
+<div id=log></div>
+<script>
+async_test(t => {
+  const frame = document.createElement("iframe");
+  t.step_timeout(() => {
+    // Make sure the iframe didn't load.
+    assert_equals(frame.contentDocument, null);
+    t.done();
+  }, 500);
+  frame.src = "/common/blank.html";
+  document.body.append(frame);
+  assert_equals(frame.contentDocument.body.localName, "body");
+}, "Top-level with anonymous policy: navigating a frame to a null policy should fail.");
+
+async_test(t => {
+  const frame = document.createElement("iframe");
+
+  const CHANNEL_NAME = "frame-anon-to-blank";
+  let bc = new BroadcastChannel(CHANNEL_NAME);
+  bc.onmessage = t.step_func((event) => {
+    assert_not_equals(frame.contentDocument, null);
+    let payload = event.data;
+    assert_equals(payload, "loaded");
+    t.step_timeout(() => {
+      assert_equals(frame.contentDocument, null, "Navigation to null policy should fail");
+      t.done();
+    }, 1500);
+  });
+
+  frame.src = `resources/navigate_anonymous.sub.html?channelName=${CHANNEL_NAME}&to=/common/blank.html`;
+  document.body.append(frame);
+  assert_equals(frame.contentDocument.body.localName, "body");
+}, "Top-level with anonymous policy: navigating a frame from an anonymous policy to a null policy should fail.");
+
+
+async_test(t => {
+  const frame = document.createElement("iframe");
+
+  const CHANNEL_NAME = "frame-usecredentials-to-blank";
+  let bc = new BroadcastChannel(CHANNEL_NAME);
+  bc.onmessage = t.step_func((event) => {
+    assert_not_equals(frame.contentDocument, null);
+    let payload = event.data;
+    assert_equals(payload, "loaded");
+    t.step_timeout(() => {
+      assert_equals(frame.contentDocument, null, "Navigation to null policy should fail");
+      t.done();
+    }, 1500);
+  });
+  frame.src = `resources/navigate_usecredentials.sub.html?channelName=${CHANNEL_NAME}&to=/common/blank.html`;
+  document.body.append(frame);
+  assert_equals(frame.contentDocument.body.localName, "body");
+}, "Top-level with anonymous policy: navigating a frame from a use-credentials policy to a null policy should fail.");
+
+async_test(t => {
+  let pageLoaded = false;
+  const CHANNEL_NAME = "anon-null-window-noopener";
+  let bc = new BroadcastChannel(CHANNEL_NAME);
+  let finished = false;
+  bc.onmessage = t.step_func((event) => {
+    let payload = event.data;
+    assert_equals(payload, "loaded");
+    pageLoaded = true;
+  });
+
+  const SECOND_CHANNEL = "anon-null-window-noopener-second";
+  let bc2 = new BroadcastChannel(SECOND_CHANNEL);
+  bc2.onmessage = t.step_func_done((event) => {
+    let payload = event.data;
+    assert_equals(payload, "loaded");
+    assert_equals(pageLoaded, true, "Opening a null window (noopener) from anon window should work");
+  });
+
+  let win = window.open(`resources/navigate_null.sub.html?channelName=${CHANNEL_NAME}&to=navigate_null.sub.html?channelName=${SECOND_CHANNEL}`, "_blank", "noopener");
+}, "Top-level with anonymous policy: creating a noopener popup with null policy should work.");
+
+async_test(t => {
+  let pageLoaded = false;
+  const CHANNEL_NAME = "anon-null-window";
+  let bc = new BroadcastChannel(CHANNEL_NAME);
+  bc.onmessage = t.step_func_done((event) => {
+    pageLoaded = true;
+    let payload = event.data;
+    assert_equals(payload, "loaded");
+  });
+
+  let win = window.open(`resources/navigate_null.sub.html?channelName=${CHANNEL_NAME}&to=/common/blank.html`, "_blank");
+  t.add_cleanup(() => win.close());
+  t.step_timeout(() => {
+    assert_equals(pageLoaded, false, "Opening a null window from anon window should fail");
+    t.done();
+  }, 500);
+}, "Top-level with anonymous policy: creating a popup with null policy should fail.");
+
+async_test(t => {
+  let pageLoaded = false;
+  const CHANNEL_NAME = "anon-null-top-navigation";
+  let bc = new BroadcastChannel(CHANNEL_NAME);
+  bc.onmessage = t.step_func((event) => {
+    pageLoaded = true;
+    let payload = event.data;
+    assert_equals(payload, "loaded");
+  });
+
+  const SECOND_CHANNEL = "anon-null-top-navigation-final";
+  let bc2 = new BroadcastChannel(SECOND_CHANNEL);
+  bc2.onmessage = t.step_func_done((event) => {
+    let payload = event.data;
+    assert_equals(payload, "loaded");
+    assert_equals(pageLoaded, true, "Opening a null window (noopener) from anon window should work");
+  });
+
+  let win = window.open(`resources/navigate_anonymous.sub.html?channelName=${CHANNEL_NAME}&to=navigate_null.sub.html?channelName=${SECOND_CHANNEL}`, "_blank", "noopener");
+
+}, "Top-level noopener with anonymous policy: navigating to a different policy should work");
+
+promise_test(t => {
+  let host_info = get_host_info();
+  return fetch(host_info.HTTP_REMOTE_ORIGIN+"/html/cross-origin/resources/nothing.txt",
+        {"mode": "no-cors", "method": "GET", "headers":{}}).then(r => {
+    assert_equals(r.type, "cors", "type should have been changed to cors");
+  });
+}, "Fetch policy: anonymous policy no-cors fetches should be changed to cors");
+
+
+async_test(t => {
+  let pageLoaded = false;
+  const CHANNEL_NAME = "anon-null-window";
+  let bc = new BroadcastChannel(CHANNEL_NAME);
+  bc.onmessage = t.step_func_done((event) => {
+    pageLoaded = true;
+    let payload = event.data;
+    assert_equals(payload, "loaded");
+  });
+
+  const SECOND_CHANNEL = "anon-null-window-second";
+  let navigated = false;
+  let bc2 = new BroadcastChannel(SECOND_CHANNEL);
+  bc2.onmessage = t.step_func((event) => {
+    navigated = true;
+    let payload = event.data;
+    assert_equals(payload, "loaded");
+  });
+
+  let win = window.open(`resources/navigate_anonymous.sub.html?channelName=${CHANNEL_NAME}&to=navigate_null.sub.html?channelName=${SECOND_CHANNEL}`, "_blank");
+  t.add_cleanup(() => win.close());
+  t.step_timeout(() => {
+    assert_equals(pageLoaded, true, "Opening the popup window from anon window should work");
+    assert_equals(navigated, false, "Navigating the popup to a null policy should fail");
+    t.done();
+  }, 500);
+}, "Top-level popup with anonymous policy: Navigating the popup to a null policy should fail.");
+
+async_test(t => {
+  let pageLoaded = false;
+  const CHANNEL_NAME = "anon-null-window";
+  let bc = new BroadcastChannel(CHANNEL_NAME);
+  bc.onmessage = t.step_func_done((event) => {
+    pageLoaded = true;
+    let payload = event.data;
+    assert_equals(payload, "loaded");
+  });
+
+  const SECOND_CHANNEL = "anon-null-window-second";
+  let navigated = false;
+  let bc2 = new BroadcastChannel(SECOND_CHANNEL);
+  bc2.onmessage = t.step_func((event) => {
+    navigated = true;
+    let payload = event.data;
+    assert_equals(payload, "loaded");
+  });
+
+  let win = window.open(`resources/navigate_anonymous.sub.html?clearOpener=true&channelName=${CHANNEL_NAME}&to=navigate_null.sub.html?channelName=${SECOND_CHANNEL}`, "_blank");
+  t.add_cleanup(() => win.close());
+  t.step_timeout(() => {
+    assert_equals(pageLoaded, true, "Opening the popup window from anon window should work");
+    assert_equals(navigated, false, "Navigating the popup to a null policy should fail");
+    t.done();
+  }, 500);
+}, "Top-level popup with anonymous policy: Navigating the popup to a null policy should fail. (even when we clear the opener)");
+
+async_test(t => {
+  let popupLoaded = false;
+  const CHANNEL_NAME = "anon-null-window-no-opener";
+  let bc = new BroadcastChannel(CHANNEL_NAME);
+  bc.onmessage = t.step_func_done((event) => {
+    let payload = event.data;
+    if (payload == "loaded") {
+      t.step_timeout(() => {
+        assert_equals(popupLoaded, true, "Opening the popup window (noopener) from anon window should work");
+        assert_equals(navigated, false, "Navigating the popup to a null policy should fail");
+        t.done();
+      }, 500);
+    } else if (payload == "popup-loaded") {
+      popupLoaded = true;
+    } else {
+      assert_unreached(`unexpected payload ${payload}`);
+    }
+  });
+
+  const SECOND_CHANNEL = "anon-null-window-second-popup";
+  let navigated = false;
+  let bc2 = new BroadcastChannel(SECOND_CHANNEL);
+  bc2.onmessage = t.step_func((event) => {
+    navigated = true;
+    let payload = event.data;
+    assert_equals(payload, "loaded");
+  });
+
+  let win = window.open(`resources/popup_and_close.sub.html?channelName=${CHANNEL_NAME}&to=navigate_null.sub.html?channelName=${SECOND_CHANNEL}`, "_blank", "noopener");
+}, "Top-level popup with anonymous policy: Navigating the popup to a null policy should fail. (even opener window is closed)");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/anonymous.tentative.html.headers b/third_party/blink/web_tests/external/wpt/html/cross-origin/anonymous.tentative.html.headers
new file mode 100644
index 0000000..a76b601
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/anonymous.tentative.html.headers
@@ -0,0 +1 @@
+Cross-Origin: anonymous
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/null.tentative.html b/third_party/blink/web_tests/external/wpt/html/cross-origin/null.tentative.html
new file mode 100644
index 0000000..ae871c4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/null.tentative.html
@@ -0,0 +1,103 @@
+<!doctype html>
+<meta name="timeout" content="long">
+<title>Cross-Origin header and nested navigable resource without such header</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/get-host-info.sub.js"></script>
+<div id=log></div>
+<script>
+async_test(t => {
+  const frame = document.createElement("iframe");
+  frame.onload = t.step_func_done(() => {
+    assert_not_equals(frame.contentDocument, null, "The frame should actually load");
+  });
+  frame.src = "/common/blank.html";
+  document.body.append(frame);
+  assert_equals(frame.contentDocument.body.localName, "body");
+}, "Top-level with null policy: navigating a frame to a null policy should work.");
+
+async_test(t => {
+  const frame = document.createElement("iframe");
+  let firstNavOk = false;
+  frame.onload = t.step_func(() => {
+    assert_not_equals(frame.contentDocument, null);
+    firstNavOk = true;
+  });
+  t.step_timeout(() => {
+    assert_equals(firstNavOk, true, "The initial load should work");
+    assert_not_equals(frame.contentDocument, null, "Navigation to null policy should fail");
+    t.done();
+  }, 500);
+  frame.src = "resources/navigate_anonymous.sub.html?to=/common/blank.html";
+  document.body.append(frame);
+  assert_equals(frame.contentDocument.body.localName, "body");
+}, "Top-level with null policy: parent policy should apply to frame navigation from use-credentials policy to a null. Should succeed.");
+
+async_test(t => {
+  const frame = document.createElement("iframe");
+  let firstNavOk = false;
+  frame.onload = t.step_func(() => {
+    assert_not_equals(frame.contentDocument, null);
+    firstNavOk = true;
+  });
+  t.step_timeout(() => {
+    assert_equals(firstNavOk, true, "The initial load should work");
+    assert_not_equals(frame.contentDocument, null, "Navigation to null policy should fail");
+    t.done();
+  }, 500);
+  frame.src = "resources/navigate_anonymous.sub.html?to=/common/blank.html";
+  document.body.append(frame);
+  assert_equals(frame.contentDocument.body.localName, "body");
+}, "Top-level with null policy: parent policy should apply to frame navigation from anonymous policy to a null. Should succeed.");
+
+async_test(t => {
+  let w = window.open(`resources/navigate_null.sub.html?to=navigate_anonymous.sub.html`, "window_name");
+
+  t.add_cleanup(() => w.close());
+
+  t.step_timeout(() => {
+    w.history.back();
+    t.step_timeout(() => {
+      assert_not_equals(w.document, null);
+      t.done();
+    }, 500);
+  }, 500);
+}, "Top-level with null policy: navigating a frame back from a blocked page should work.");
+
+async_test(t => {
+  let pageLoaded = false;
+  const CHANNEL_NAME = "usecredentials-null-top-navigation";
+  let bc = new BroadcastChannel(CHANNEL_NAME);
+  let finished = false;
+  bc.onmessage = t.step_func((event) => {
+    pageLoaded = true;
+    let payload = event.data;
+    assert_equals(payload, "loaded");
+  });
+
+  const SECOND_CHANNEL = "usecredentials-null-top-navigation-final";
+  let bc2 = new BroadcastChannel(SECOND_CHANNEL);
+  bc2.onmessage = t.step_func((event) => {
+    finished = true;
+    let payload = event.data;
+    assert_equals(payload, "loaded");
+  });
+
+  let win = window.open(`resources/navigate_usecredentials.sub.html?channelName=${CHANNEL_NAME}&to=navigate_null.sub.html?channelName=${SECOND_CHANNEL}`, "_blank", "noopener");
+
+  t.step_timeout(() => {
+    assert_equals(pageLoaded, true, "Opening a null window (noopener) from usecredentials window should work");
+    assert_equals(finished, true, "Navigating a top level window out of an usecredentials policy should work");
+    t.done();
+  }, 500);
+}, "Top-level noopener popup with use-credentials policy: navigating to a different (null) policy should work");
+
+promise_test(t => {
+  let host_info = get_host_info();
+  return fetch(host_info.HTTP_REMOTE_ORIGIN+"/html/cross-origin/resources/nothing.txt",
+        {"mode": "no-cors", "method": "GET", "headers":{}}).then(r => {
+    assert_equals(r.type, "opaque", "type should be opaque for cross origin fetch");
+  });
+}, "Fetch policy: null policy should not affect the no-cors mode");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/null.tentative.html.headers b/third_party/blink/web_tests/external/wpt/html/cross-origin/null.tentative.html.headers
new file mode 100644
index 0000000..fd34f12
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/null.tentative.html.headers
@@ -0,0 +1 @@
+Cross-Origin: unknown-should-be-parsed-as-null
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_anonymous.sub.html b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_anonymous.sub.html
new file mode 100644
index 0000000..d4b38bc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_anonymous.sub.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<script>
+  let current = new URL(window.location.href);
+  let navigateTo = current.searchParams.get("to");
+  let channelName = current.searchParams.get("channelName");
+  let clearOpener = current.searchParams.get("clearOpener");
+
+  if (clearOpener) {
+    window.opener = null;
+  }
+
+  current.search = "";
+  if (navigateTo) {
+    let next = new URL(navigateTo, current);
+    setTimeout(() => {
+      window.location = next.href;
+    }, 50);
+  }
+
+  if (channelName) {
+    let bc = new BroadcastChannel(channelName);
+    bc.postMessage("loaded");
+  }
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_anonymous.sub.html.headers b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_anonymous.sub.html.headers
new file mode 100644
index 0000000..a76b601
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_anonymous.sub.html.headers
@@ -0,0 +1 @@
+Cross-Origin: anonymous
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_null.sub.html b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_null.sub.html
new file mode 100644
index 0000000..1008f70
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_null.sub.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<script>
+  let current = new URL(window.location.href);
+  let navigateTo = current.searchParams.get("to");
+  let channelName = current.searchParams.get("channelName");
+  current.search = "";
+  if (navigateTo) {
+    let next = new URL(navigateTo, current);
+    setTimeout(() => {
+      window.location = next.href;
+    }, 50);
+  }
+
+  if (channelName) {
+    let bc = new BroadcastChannel(channelName);
+    bc.postMessage("loaded");
+  }
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_usecredentials.sub.html b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_usecredentials.sub.html
new file mode 100644
index 0000000..1008f70
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_usecredentials.sub.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<script>
+  let current = new URL(window.location.href);
+  let navigateTo = current.searchParams.get("to");
+  let channelName = current.searchParams.get("channelName");
+  current.search = "";
+  if (navigateTo) {
+    let next = new URL(navigateTo, current);
+    setTimeout(() => {
+      window.location = next.href;
+    }, 50);
+  }
+
+  if (channelName) {
+    let bc = new BroadcastChannel(channelName);
+    bc.postMessage("loaded");
+  }
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_usecredentials.sub.html.headers b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_usecredentials.sub.html.headers
new file mode 100644
index 0000000..a84d378
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/navigate_usecredentials.sub.html.headers
@@ -0,0 +1 @@
+Cross-Origin: use-credentials
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/nothing.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/nothing.txt
new file mode 100644
index 0000000..9dafe9b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/nothing.txt
@@ -0,0 +1 @@
+nothing
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/nothing.txt.headers b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/nothing.txt.headers
new file mode 100644
index 0000000..cb762eff
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/nothing.txt.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/popup_and_close.sub.html b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/popup_and_close.sub.html
new file mode 100644
index 0000000..2489fa8d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/popup_and_close.sub.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<script>
+  let current = new URL(window.location.href);
+  let navigateTo = current.searchParams.get("to");
+  let channelName = current.searchParams.get("channelName");
+  let secondChannel = current.searchParams.get("secondChannel");
+
+  if (channelName) {
+    let bc = new BroadcastChannel(channelName);
+    bc.postMessage("popup-loaded");
+  }
+
+  let win = window.open(`navigate_anonymous.sub.html?channelName=${channelName}&to=navigate_null.sub.html?channelName=${secondChannel}`, "_blank");
+
+  setTimeout(() => {
+    window.close();
+  }, 10);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/popup_and_close.sub.html.headers b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/popup_and_close.sub.html.headers
new file mode 100644
index 0000000..a76b601
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/resources/popup_and_close.sub.html.headers
@@ -0,0 +1 @@
+Cross-Origin: anonymous
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/usecredentials.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin/usecredentials.tentative-expected.txt
new file mode 100644
index 0000000..f65e026
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/usecredentials.tentative-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+FAIL Top-level with use-credentials policy: navigating a frame to a null policy should fail. assert_equals: expected null but got Document node with 1 child
+FAIL Top-level with use-credentials policy: navigating a frame from a use-credentials policy to a null policy should fail assert_equals: Navigation to null policy should fail expected null but got Document node with 1 child
+FAIL Top-level with use-credentials policy: navigating a frame from an anonymous policy to a null policy should fail. assert_equals: Navigation to null policy should fail expected null but got Document node with 1 child
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/usecredentials.tentative.html b/third_party/blink/web_tests/external/wpt/html/cross-origin/usecredentials.tentative.html
new file mode 100644
index 0000000..55c0f2235
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/usecredentials.tentative.html
@@ -0,0 +1,54 @@
+<!doctype html>
+<meta name="timeout" content="long">
+<title>Cross-Origin header and nested navigable resource without such header</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<script>
+async_test(t => {
+  const frame = document.createElement("iframe");
+  t.step_timeout(() => {
+    // Make sure the iframe didn't load.
+    assert_equals(frame.contentDocument, null);
+    t.done();
+  }, 500);
+  frame.src = "/common/blank.html";
+  document.body.append(frame);
+  assert_equals(frame.contentDocument.body.localName, "body");
+}, "Top-level with use-credentials policy: navigating a frame to a null policy should fail.");
+
+async_test(t => {
+  const frame = document.createElement("iframe");
+  let firstNavOk = false;
+  frame.onload = t.step_func(() => {
+    assert_not_equals(frame.contentDocument, null);
+    firstNavOk = true;
+  });
+  t.step_timeout(() => {
+    assert_equals(firstNavOk, true, "The initial load should work");
+    assert_equals(frame.contentDocument, null, "Navigation to null policy should fail");
+    t.done();
+  }, 500);
+  frame.src = "resources/navigate_usecredentials.sub.html?to=/common/blank.html";
+  document.body.append(frame);
+  assert_equals(frame.contentDocument.body.localName, "body");
+}, "Top-level with use-credentials policy: navigating a frame from a use-credentials policy to a null policy should fail");
+
+async_test(t => {
+  const frame = document.createElement("iframe");
+  let firstNavOk = false;
+  frame.onload = t.step_func(() => {
+    assert_not_equals(frame.contentDocument, null);
+    firstNavOk = true;
+  });
+  t.step_timeout(() => {
+    assert_equals(firstNavOk, true, "The initial load should work");
+    assert_equals(frame.contentDocument, null, "Navigation to null policy should fail");
+    t.done();
+  }, 500);
+  frame.src = "resources/navigate_anonymous.sub.html?to=/common/blank.html";
+  document.body.append(frame);
+  assert_equals(frame.contentDocument.body.localName, "body");
+}, "Top-level with use-credentials policy: navigating a frame from an anonymous policy to a null policy should fail.");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin/usecredentials.tentative.html.headers b/third_party/blink/web_tests/external/wpt/html/cross-origin/usecredentials.tentative.html.headers
new file mode 100644
index 0000000..a84d378
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin/usecredentials.tentative.html.headers
@@ -0,0 +1 @@
+Cross-Origin: use-credentials
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/page-visibility.idl b/third_party/blink/web_tests/external/wpt/interfaces/page-visibility.idl
index 28fda2c..6b8bd52 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/page-visibility.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/page-visibility.idl
@@ -4,7 +4,7 @@
 // Source: Page Visibility Level 2 (https://w3c.github.io/page-visibility/)
 
 enum VisibilityState {
-  "hidden", "visible", "prerender"
+  "hidden", "visible"
 };
 
 partial interface Document {
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/performance-timeline.idl b/third_party/blink/web_tests/external/wpt/interfaces/performance-timeline.idl
index 51752b13..8ded59d 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/performance-timeline.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/performance-timeline.idl
@@ -26,7 +26,7 @@
   void observe(optional PerformanceObserverInit options);
   void disconnect();
   PerformanceEntryList takeRecords();
-  static readonly attribute FrozenArray<DOMString> supportedEntryTypes;
+  [SameObject] static readonly attribute FrozenArray<DOMString> supportedEntryTypes;
 };
 
 dictionary PerformanceObserverInit {
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/web-nfc.idl b/third_party/blink/web_tests/external/wpt/interfaces/web-nfc.idl
index a570916..26f32a0 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/web-nfc.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/web-nfc.idl
@@ -4,9 +4,8 @@
 // Source: Web NFC API (https://w3c.github.io/web-nfc/)
 
 dictionary NDEFMessage {
-  DOMString? serialNumber;
-  sequence<NDEFRecord> records;
   USVString url;
+  sequence<NDEFRecord> records;
 };
 
 typedef (DOMString or unrestricted double or ArrayBuffer or Dictionary) NDEFRecordData;
@@ -43,10 +42,12 @@
 
 [Constructor(DOMString type, NFCReadingEventInit readingEventInitDict), SecureContext, Exposed=Window]
 interface NFCReadingEvent : Event {
+  readonly attribute DOMString serialNumber;
   readonly attribute NDEFMessage message;
 };
 
 dictionary NFCReadingEventInit : EventInit {
+  DOMString? serialNumber = "";
   required NDEFMessage message;
 };
 
diff --git a/third_party/blink/web_tests/external/wpt/intersection-observer/root-margin-rounding.html b/third_party/blink/web_tests/external/wpt/intersection-observer/root-margin-rounding.html
new file mode 100644
index 0000000..f5e3323
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/root-margin-rounding.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta name="viewport" content="width=device-width,initial-scale=1">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-rootmargin">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1553673">
+<style>
+  html { width: 100vw; height: 100vh }
+</style>
+<script>
+const t = async_test("IntersectionObserver root margin cannot end up with negative rect (and thus non-intersecting) due to rounding");
+
+let remainingTests = 100;
+
+// This is just a best-effort test to catch issues.
+for (let i = 0; i < 100; ++i) {
+  let offset = i / 100;
+  let observer;
+  observer = new IntersectionObserver(t.step_func(function(entries) {
+    assert_equals(entries.length, 1);
+    assert_equals(entries[0].target, document.documentElement);
+    assert_true(entries[0].isIntersecting, "should be intersecting at " + offset);
+    if (!--remainingTests)
+      t.done();
+    observer.disconnect();
+  }), { rootMargin: `${-100 * (1 - offset)}% 0px ${-100 * offset}%` });
+  observer.observe(document.documentElement);
+}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/lint.whitelist b/third_party/blink/web_tests/external/wpt/lint.whitelist
index f17a929..be52aa6 100644
--- a/third_party/blink/web_tests/external/wpt/lint.whitelist
+++ b/third_party/blink/web_tests/external/wpt/lint.whitelist
@@ -168,6 +168,7 @@
 SET TIMEOUT: html/browsers/history/the-session-history-of-browsing-contexts/*
 SET TIMEOUT: html/browsers/offline/*
 SET TIMEOUT: html/browsers/the-window-object/*
+SET TIMEOUT: html/cross-origin/resources/*
 SET TIMEOUT: html/editing/dnd/*
 SET TIMEOUT: html/semantics/embedded-content/the-iframe-element/*
 SET TIMEOUT: html/semantics/embedded-content/the-img-element/*
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/lengths-2-ref.html b/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/lengths-2-ref.html
deleted file mode 100644
index 9fca6f496..0000000
--- a/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/lengths-2-ref.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8"/>
-<title>MathML lengths (reference)</title>
-</head>
-<body>
-  <p>Test passes if there is a green square and no red.</p>
-  <div>
-    <div id="red" style="position: absolute; width: 200px; height: 200px; background: green;">
-    </div>
-  </div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/lengths-2.html b/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/lengths-2.html
index 37cc640..aa38e97 100644
--- a/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/lengths-2.html
+++ b/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/lengths-2.html
@@ -1,122 +1,159 @@
 <!DOCTYPE html>
 <html>
 <head>
-<meta charset="utf-8"/>
+<meta charset="utf-8">
 <title>MathML lengths</title>
 <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#cssstyling"/>
-<link rel="match" href="lengths-2-ref.html"/>
-<meta name="assert" content="Verify whether the different namedspaces are accepted for MathML lengths.">
+<meta name="assert" content="Verify various cases of the MathML length syntax.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <style>
   @font-face {
     font-family: TestFont;
     src: url("/fonts/math/xheight500.woff");
   }
-  mpadded {
+  math {
     font-family: TestFont;
-    font-size: 200px; /* 1em = 200px */
-  }
-  div {
-    position: absolute;
-  }
-  #red mspace {
-    background: red;
-  }
-  #green mspace {
-    background: green;
+    font-size: 10px;
   }
 </style>
+<script>
+  var epsilon = .5;
+
+  function getBox(aId) {
+    return document.getElementById(aId).getBoundingClientRect();
+  }
+
+  setup({ explicit_done: true });
+  window.addEventListener("load", function() {
+    // Delay the check to workaround WebKit's bug https://webkit.org/b/174030.
+    requestAnimationFrame(() => { document.fonts.ready.then(runTests); });
+  });
+
+  function runTests() {
+    test(function() {
+      assert_equals(getBox("unitCm").width, 96, "cm");
+      assert_equals(getBox("unitEm").width, 120, "em");
+      assert_equals(getBox("unitEx").width, 500, "ex");
+      assert_equals(getBox("unitIn").width, 288, "in");
+      assert_equals(getBox("unitNamed").width, 700, "namedspace");
+      assert_equals(getBox("unitMm").width, 576, "mm");
+      assert_equals(getBox("unitPc").width, 96, "pc");
+      assert_equals(getBox("unitPercentage").width, 60, "%");
+      assert_equals(getBox("unitPt").width, 96, "pt");
+      assert_equals(getBox("unitPx").width, 123, "px");
+      assert_equals(getBox("unitNone").width, 150, "Unitless");
+    }, "Units");
+
+    test(function() {
+      assert_equals(getBox("spaceCm").width, 96, "cm");
+      assert_equals(getBox("spaceEm").width, 120, "em");
+      assert_equals(getBox("spaceEx").width, 500, "ex");
+      assert_equals(getBox("spaceIn").width, 288, "in");
+      assert_equals(getBox("spaceNamed").width, 700, "namedspace");
+      assert_equals(getBox("spaceMm").width, 576, "mm");
+      assert_equals(getBox("spacePc").width, 96, "pc");
+      assert_equals(getBox("spacePercentage").width, 60, "%");
+      assert_equals(getBox("spacePt").width, 96, "pt");
+      assert_equals(getBox("spacePx").width, 123, "px");
+      assert_equals(getBox("spaceNone").width, 150, "Unitless");
+    }, "Trimming of space");
+
+    test(function() {
+      assert_approx_equals(getBox("n0").width, 0, epsilon, "n0");
+      assert_approx_equals(getBox("n1").width, 90, epsilon, "n1");
+      assert_approx_equals(getBox("n2").width, 8, epsilon, "n2");
+      assert_approx_equals(getBox("n3").width, 70, epsilon, "n3");
+      assert_approx_equals(getBox("n4").width, 650, epsilon, "n4");
+      assert_approx_equals(getBox("n5").width, 4320, epsilon, "n5");
+      assert_approx_equals(getBox("n6").width, 1, epsilon, "n6");
+      assert_approx_equals(getBox("n7").width, 8, epsilon, "n7");
+      assert_approx_equals(getBox("n8").width, 65, epsilon, "n8");
+      assert_approx_equals(getBox("n9").width, 432, epsilon, "n9");
+      assert_approx_equals(getBox("n10").width, 123, epsilon, "n10");
+    }, "Non-negative numbers");
+
+    test(function() {
+      var topRef = getBox("ref").top;
+      assert_approx_equals(getBox("N0").top - topRef, -0, epsilon, "N0");
+      assert_approx_equals(topRef - getBox("N1").top, -90, epsilon, "N1");
+      assert_approx_equals(topRef - getBox("N2").top, -8, epsilon, "N2");
+      assert_approx_equals(topRef - getBox("N3").top, -70, epsilon, "N3");
+      assert_approx_equals(topRef - getBox("N4").top, -650, epsilon, "N4");
+      assert_approx_equals(topRef - getBox("N5").top, -4320, epsilon, "N5");
+      assert_approx_equals(topRef - getBox("N6").top, -1, epsilon, "N6");
+      assert_approx_equals(topRef - getBox("N7").top, -8, epsilon, "N7");
+      assert_approx_equals(topRef - getBox("N8").top, -65, epsilon, "N8");
+      assert_approx_equals(topRef - getBox("N9").top, -432, epsilon, "N9");
+      assert_approx_equals(topRef - getBox("N10").top, -123, epsilon, "N10");
+    }, "Non-positive numbers");
+
+    done();
+  }
+</script>
 </head>
 <body>
-  <p>Test passes if there is a green square and no red.</p>
-  <div>
-    <div id="red" style="position: absolute; width: 200px; height: 200px; background: green;">
-      <!-- veryverythinmathspace -->
-      <div style="left: 0px;"><math><mpadded height="100px" depth="100px" voffset="1veryverythinmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 10px;"><math><mpadded height="100px" depth="100px" voffset="0.05555555555555556em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- verythinmathspace -->
-      <div style="left: 20px;"><math><mpadded height="100px" depth="100px" voffset="1verythinmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 30px;"><math><mpadded height="100px" depth="100px" voffset="0.1111111111111111em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- thinmathspace -->
-      <div style="left: 40px;"><math><mpadded height="100px" depth="100px" voffset="1thinmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 50px;"><math><mpadded height="100px" depth="100px" voffset="0.1666666666666667em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- mediummathspace -->
-      <div style="left: 60px;"><math><mpadded height="100px" depth="100px" voffset="1mediummathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 70px;"><math><mpadded height="100px" depth="100px" voffset="0.2222222222222222em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- thickmathspace -->
-      <div style="left: 80px;"><math><mpadded height="100px" depth="100px" voffset="1thickmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 90px;"><math><mpadded height="100px" depth="100px" voffset="0.2777777777777778em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- verythickmathspace -->
-      <div style="left: 100px;"><math><mpadded height="100px" depth="100px" voffset="1verythickmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 110px;"><math><mpadded height="100px" depth="100px" voffset="0.3333333333333333em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- veryverythickmathspace -->
-      <div style="left: 120px;"><math><mpadded height="100px" depth="100px" voffset="1veryverythickmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 130px;"><math><mpadded height="100px" depth="100px" voffset="0.3888888888888889em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- negativeveryverythinmathspace -->
-      <div style="left: 0px;"><math><mpadded height="100px" depth="100px" voffset="1negativeveryverythinmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 10px;"><math><mpadded height="100px" depth="100px" voffset="-0.05555555555555556em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- negativeverythinmathspace -->
-      <div style="left: 20px;"><math><mpadded height="100px" depth="100px" voffset="1negativeverythinmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 30px;"><math><mpadded height="100px" depth="100px" voffset="-0.1111111111111111em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- negativethinmathspace -->
-      <div style="left: 40px;"><math><mpadded height="100px" depth="100px" voffset="1negativethinmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 50px;"><math><mpadded height="100px" depth="100px" voffset="-0.1666666666666667em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- negativemediummathspace -->
-      <div style="left: 60px;"><math><mpadded height="100px" depth="100px" voffset="1negativemediummathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 70px;"><math><mpadded height="100px" depth="100px" voffset="-0.2222222222222222em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- negativethickmathspace -->
-      <div style="left: 80px;"><math><mpadded height="100px" depth="100px" voffset="1negativethickmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 90px;"><math><mpadded height="100px" depth="100px" voffset="-0.2777777777777778em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- negativeverythickmathspace -->
-      <div style="left: 100px;"><math><mpadded height="100px" depth="100px" voffset="1negativeverythickmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 110px;"><math><mpadded height="100px" depth="100px" voffset="-0.3333333333333333em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- negativeveryverythickmathspace -->
-      <div style="left: 120px;"><math><mpadded height="100px" depth="100px" voffset="1negativeveryverythickmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 130px;"><math><mpadded height="100px" depth="100px" voffset="-0.3888888888888889em"><mspace width="10px" height="10px"/></mpadded></math></div>
-    </div>
-    <div id="green" style="position: absolute; width: 200px; height: 200px;">
-      <!-- veryverythinmathspace -->
-      <div style="left: 10px;"><math><mpadded height="100px" depth="100px" voffset="1veryverythinmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 0px;"><math><mpadded height="100px" depth="100px" voffset="0.05555555555555556em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- verythinmathspace -->
-      <div style="left: 30px;"><math><mpadded height="100px" depth="100px" voffset="1verythinmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 20px;"><math><mpadded height="100px" depth="100px" voffset="0.1111111111111111em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- thinmathspace -->
-      <div style="left: 50px;"><math><mpadded height="100px" depth="100px" voffset="1thinmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 40px;"><math><mpadded height="100px" depth="100px" voffset="0.1666666666666667em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- mediummathspace -->
-      <div style="left: 70px;"><math><mpadded height="100px" depth="100px" voffset="1mediummathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 60px;"><math><mpadded height="100px" depth="100px" voffset="0.2222222222222222em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- thickmathspace -->
-      <div style="left: 90px;"><math><mpadded height="100px" depth="100px" voffset="1thickmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 80px;"><math><mpadded height="100px" depth="100px" voffset="0.2777777777777778em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- verythickmathspace -->
-      <div style="left: 110px;"><math><mpadded height="100px" depth="100px" voffset="1verythickmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 100px;"><math><mpadded height="100px" depth="100px" voffset="0.3333333333333333em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- veryverythickmathspace -->
-      <div style="left: 130px;"><math><mpadded height="100px" depth="100px" voffset="1veryverythickmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 120px;"><math><mpadded height="100px" depth="100px" voffset="0.3888888888888889em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- negativeveryverythinmathspace -->
-      <div style="left: 10px;"><math><mpadded height="100px" depth="100px" voffset="1negativeveryverythinmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 0px;"><math><mpadded height="100px" depth="100px" voffset="-0.05555555555555556em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- negativeverythinmathspace -->
-      <div style="left: 30px;"><math><mpadded height="100px" depth="100px" voffset="1negativeverythinmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 20px;"><math><mpadded height="100px" depth="100px" voffset="-0.1111111111111111em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- negativethinmathspace -->
-      <div style="left: 50px;"><math><mpadded height="100px" depth="100px" voffset="1negativethinmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 40px;"><math><mpadded height="100px" depth="100px" voffset="-0.1666666666666667em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- negativemediummathspace -->
-      <div style="left: 70px;"><math><mpadded height="100px" depth="100px" voffset="1negativemediummathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 60px;"><math><mpadded height="100px" depth="100px" voffset="-0.2222222222222222em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- negativethickmathspace -->
-      <div style="left: 90px;"><math><mpadded height="100px" depth="100px" voffset="1negativethickmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 80px;"><math><mpadded height="100px" depth="100px" voffset="-0.2777777777777778em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- negativeverythickmathspace -->
-      <div style="left: 110px;"><math><mpadded height="100px" depth="100px" voffset="1negativeverythickmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 100px;"><math><mpadded height="100px" depth="100px" voffset="-0.3333333333333333em"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <!-- negativeveryverythickmathspace -->
-      <div style="left: 130px;"><math><mpadded height="100px" depth="100px" voffset="1negativeveryverythickmathspace"><mspace width="10px" height="10px"/></mpadded></math></div>
-      <div style="left: 120px;"><math><mpadded height="100px" depth="100px" voffset="-0.3888888888888889em"><mspace width="10px" height="10px"/></mpadded></math></div>
-    </div>
-  </div>
+  <div id="log"></div>
+  <p>
+    <math>
+      <mspace id="unitCm" width="2.54cm"/>
+      <mspace id="unitEm" width="12em"/>
+      <mspace id="unitEx" width="100ex"/>
+      <mspace id="unitIn" width="3in"/>
+      <mspace style="font-size: 1800px" id="unitNamed" width="veryverythickmathspace"/>
+      <mspace id="unitMm" width="152.4mm"/>
+      <mspace id="unitPc" width="6pc"/>
+      <mstyle mathsize="200%"><mspace id="unitPercentage" width="3em"/></mstyle>
+      <mspace id="unitPt" width="72pt"/>
+      <mspace id="unitPx" width="123px"/>
+      <mstyle mathsize="5"><mspace id="unitNone" width="3em"/></mstyle>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mspace id="spaceCm" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;2.54cm&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+      <mspace id="spaceEm" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;12em&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+      <mspace id="spaceEx" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;100ex&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+      <mspace id="spaceIn" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;3in&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+      <mspace style="font-size: 1800px" id="spaceNamed" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;veryverythickmathspace&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+      <mspace id="spaceMm" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;152.4mm&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+      <mspace id="spacePc" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;6pc&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+      <mstyle mathsize="200%"><mspace id="spacePercentage" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;3em&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/></mstyle>
+      <mspace id="spacePt" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;72pt&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+      <mspace id="spacePx" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;123px&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+      <mstyle mathsize="5"><mspace id="spaceNone" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;3em&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/></mstyle>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mspace id="n0" width="0em"/>
+      <mspace id="n1" width="9em"/>
+      <mspace id="n2" width=".8em"/>
+      <mspace id="n3" width="7.em"/>
+      <mspace id="n4" width="65em"/>
+      <mspace id="n5" width="432em"/>
+      <mspace id="n6" width=".10em"/>
+      <mspace id="n7" width=".789em"/>
+      <mspace id="n8" width="6.5em"/>
+      <mspace id="n9" width="43.21em"/>
+      <mspace id="n10" width="012.345em"/>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mspace id="ref"></mspace>
+      <mpadded voffset="-0em"><mspace id="N0"/></mpadded>
+      <mpadded voffset="-9em"><mspace id="N1"/></mpadded>
+      <mpadded voffset="-.8em"><mspace id="N2"/></mpadded>
+      <mpadded voffset="-7.em"><mspace id="N3"/></mpadded>
+      <mpadded voffset="-65em"><mspace id="N4"/></mpadded>
+      <mpadded voffset="-432em"><mspace id="N5"/></mpadded>
+      <mpadded voffset="-.10em"><mspace id="N6"/></mpadded>
+      <mpadded voffset="-.789em"><mspace id="N7"/></mpadded>
+      <mpadded voffset="-6.5em"><mspace id="N8"/></mpadded>
+      <mpadded voffset="-43.21em"><mspace id="N9"/></mpadded>
+      <mpadded voffset="-012.345em"><mspace id="N10"/></mpadded>
+    </math>
+  </p>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/lengths-3.html b/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/lengths-3.html
deleted file mode 100644
index aa38e97..0000000
--- a/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/lengths-3.html
+++ /dev/null
@@ -1,159 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<title>MathML lengths</title>
-<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#cssstyling"/>
-<meta name="assert" content="Verify various cases of the MathML length syntax.">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<style>
-  @font-face {
-    font-family: TestFont;
-    src: url("/fonts/math/xheight500.woff");
-  }
-  math {
-    font-family: TestFont;
-    font-size: 10px;
-  }
-</style>
-<script>
-  var epsilon = .5;
-
-  function getBox(aId) {
-    return document.getElementById(aId).getBoundingClientRect();
-  }
-
-  setup({ explicit_done: true });
-  window.addEventListener("load", function() {
-    // Delay the check to workaround WebKit's bug https://webkit.org/b/174030.
-    requestAnimationFrame(() => { document.fonts.ready.then(runTests); });
-  });
-
-  function runTests() {
-    test(function() {
-      assert_equals(getBox("unitCm").width, 96, "cm");
-      assert_equals(getBox("unitEm").width, 120, "em");
-      assert_equals(getBox("unitEx").width, 500, "ex");
-      assert_equals(getBox("unitIn").width, 288, "in");
-      assert_equals(getBox("unitNamed").width, 700, "namedspace");
-      assert_equals(getBox("unitMm").width, 576, "mm");
-      assert_equals(getBox("unitPc").width, 96, "pc");
-      assert_equals(getBox("unitPercentage").width, 60, "%");
-      assert_equals(getBox("unitPt").width, 96, "pt");
-      assert_equals(getBox("unitPx").width, 123, "px");
-      assert_equals(getBox("unitNone").width, 150, "Unitless");
-    }, "Units");
-
-    test(function() {
-      assert_equals(getBox("spaceCm").width, 96, "cm");
-      assert_equals(getBox("spaceEm").width, 120, "em");
-      assert_equals(getBox("spaceEx").width, 500, "ex");
-      assert_equals(getBox("spaceIn").width, 288, "in");
-      assert_equals(getBox("spaceNamed").width, 700, "namedspace");
-      assert_equals(getBox("spaceMm").width, 576, "mm");
-      assert_equals(getBox("spacePc").width, 96, "pc");
-      assert_equals(getBox("spacePercentage").width, 60, "%");
-      assert_equals(getBox("spacePt").width, 96, "pt");
-      assert_equals(getBox("spacePx").width, 123, "px");
-      assert_equals(getBox("spaceNone").width, 150, "Unitless");
-    }, "Trimming of space");
-
-    test(function() {
-      assert_approx_equals(getBox("n0").width, 0, epsilon, "n0");
-      assert_approx_equals(getBox("n1").width, 90, epsilon, "n1");
-      assert_approx_equals(getBox("n2").width, 8, epsilon, "n2");
-      assert_approx_equals(getBox("n3").width, 70, epsilon, "n3");
-      assert_approx_equals(getBox("n4").width, 650, epsilon, "n4");
-      assert_approx_equals(getBox("n5").width, 4320, epsilon, "n5");
-      assert_approx_equals(getBox("n6").width, 1, epsilon, "n6");
-      assert_approx_equals(getBox("n7").width, 8, epsilon, "n7");
-      assert_approx_equals(getBox("n8").width, 65, epsilon, "n8");
-      assert_approx_equals(getBox("n9").width, 432, epsilon, "n9");
-      assert_approx_equals(getBox("n10").width, 123, epsilon, "n10");
-    }, "Non-negative numbers");
-
-    test(function() {
-      var topRef = getBox("ref").top;
-      assert_approx_equals(getBox("N0").top - topRef, -0, epsilon, "N0");
-      assert_approx_equals(topRef - getBox("N1").top, -90, epsilon, "N1");
-      assert_approx_equals(topRef - getBox("N2").top, -8, epsilon, "N2");
-      assert_approx_equals(topRef - getBox("N3").top, -70, epsilon, "N3");
-      assert_approx_equals(topRef - getBox("N4").top, -650, epsilon, "N4");
-      assert_approx_equals(topRef - getBox("N5").top, -4320, epsilon, "N5");
-      assert_approx_equals(topRef - getBox("N6").top, -1, epsilon, "N6");
-      assert_approx_equals(topRef - getBox("N7").top, -8, epsilon, "N7");
-      assert_approx_equals(topRef - getBox("N8").top, -65, epsilon, "N8");
-      assert_approx_equals(topRef - getBox("N9").top, -432, epsilon, "N9");
-      assert_approx_equals(topRef - getBox("N10").top, -123, epsilon, "N10");
-    }, "Non-positive numbers");
-
-    done();
-  }
-</script>
-</head>
-<body>
-  <div id="log"></div>
-  <p>
-    <math>
-      <mspace id="unitCm" width="2.54cm"/>
-      <mspace id="unitEm" width="12em"/>
-      <mspace id="unitEx" width="100ex"/>
-      <mspace id="unitIn" width="3in"/>
-      <mspace style="font-size: 1800px" id="unitNamed" width="veryverythickmathspace"/>
-      <mspace id="unitMm" width="152.4mm"/>
-      <mspace id="unitPc" width="6pc"/>
-      <mstyle mathsize="200%"><mspace id="unitPercentage" width="3em"/></mstyle>
-      <mspace id="unitPt" width="72pt"/>
-      <mspace id="unitPx" width="123px"/>
-      <mstyle mathsize="5"><mspace id="unitNone" width="3em"/></mstyle>
-    </math>
-  </p>
-  <p>
-    <math>
-      <mspace id="spaceCm" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;2.54cm&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
-      <mspace id="spaceEm" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;12em&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
-      <mspace id="spaceEx" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;100ex&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
-      <mspace id="spaceIn" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;3in&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
-      <mspace style="font-size: 1800px" id="spaceNamed" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;veryverythickmathspace&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
-      <mspace id="spaceMm" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;152.4mm&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
-      <mspace id="spacePc" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;6pc&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
-      <mstyle mathsize="200%"><mspace id="spacePercentage" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;3em&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/></mstyle>
-      <mspace id="spacePt" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;72pt&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
-      <mspace id="spacePx" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;123px&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
-      <mstyle mathsize="5"><mspace id="spaceNone" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;3em&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/></mstyle>
-    </math>
-  </p>
-  <p>
-    <math>
-      <mspace id="n0" width="0em"/>
-      <mspace id="n1" width="9em"/>
-      <mspace id="n2" width=".8em"/>
-      <mspace id="n3" width="7.em"/>
-      <mspace id="n4" width="65em"/>
-      <mspace id="n5" width="432em"/>
-      <mspace id="n6" width=".10em"/>
-      <mspace id="n7" width=".789em"/>
-      <mspace id="n8" width="6.5em"/>
-      <mspace id="n9" width="43.21em"/>
-      <mspace id="n10" width="012.345em"/>
-    </math>
-  </p>
-  <p>
-    <math>
-      <mspace id="ref"></mspace>
-      <mpadded voffset="-0em"><mspace id="N0"/></mpadded>
-      <mpadded voffset="-9em"><mspace id="N1"/></mpadded>
-      <mpadded voffset="-.8em"><mspace id="N2"/></mpadded>
-      <mpadded voffset="-7.em"><mspace id="N3"/></mpadded>
-      <mpadded voffset="-65em"><mspace id="N4"/></mpadded>
-      <mpadded voffset="-432em"><mspace id="N5"/></mpadded>
-      <mpadded voffset="-.10em"><mspace id="N6"/></mpadded>
-      <mpadded voffset="-.789em"><mspace id="N7"/></mpadded>
-      <mpadded voffset="-6.5em"><mspace id="N8"/></mpadded>
-      <mpadded voffset="-43.21em"><mspace id="N9"/></mpadded>
-      <mpadded voffset="-012.345em"><mspace id="N10"/></mpadded>
-    </math>
-  </p>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStream-MediaElement-firstframe.https-expected.txt b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStream-MediaElement-firstframe.https-expected.txt
new file mode 100644
index 0000000..8b4583f6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStream-MediaElement-firstframe.https-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught Error: Got unexpected event undefined
+PASS Tests that loading a MediaStream in a media element eventually results in "canplay" even when not playing or autoplaying
+PASS Tests that loading a MediaStream in a media element sees all the expected (deterministic) events even when not playing or autoplaying
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html
new file mode 100644
index 0000000..1c629245
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html
@@ -0,0 +1,99 @@
+<!doctype html>
+<html>
+<head>
+<title>Assigning a MediaStream to a media element and not playing it results in rendering a first frame</title>
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that a HTMLMediaElement with an
+assigned MediaStream with a video track fires the appropriate events to reach
+the "canplay" event and readyState HAVE_ENOUGH_DATA even when not playing or
+autoplaying.</p>
+<video id="vid"></video>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+'use strict';
+const vid = document.getElementById("vid");
+
+promise_test(async t => {
+  const wait = ms => new Promise(r => t.step_timeout(r, ms));
+  const timeout = (promise, time, msg) => Promise.race([
+    promise,
+    wait(time).then(() => Promise.reject(new Error(msg)))
+  ]);
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+  vid.srcObject = stream;
+
+  await timeout(new Promise(r => vid.oncanplay = r), 8000, "canplay timeout");
+  assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+    "readyState is HAVE_ENOUGH_DATA after \"canplay\"");
+}, "Tests that loading a MediaStream in a media element eventually results in \"canplay\" even when not playing or autoplaying");
+
+promise_test(async t => {
+  const wait = ms => new Promise(r => t.step_timeout(r, ms));
+  const timeout = (promise, time, msg) => Promise.race([
+    promise,
+    wait(time).then(() => Promise.reject(new Error(msg)))
+  ]);
+  const unexpected = e => { throw new Error(`Got unexpected event ${e.name}`); };
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+  vid.srcObject = stream;
+
+  vid.onloadstart = unexpected;
+  vid.ondurationchange = unexpected;
+  vid.onresize = unexpected;
+  vid.onloadedmetadata = unexpected;
+  vid.onloadeddata = unexpected;
+  vid.oncanplay = unexpected;
+  vid.oncanplaythrough = unexpected;
+
+  await timeout(new Promise(r => vid.onloadstart = r), 8000,
+    "loadstart timeout");
+  vid.onloadstart = unexpected;
+
+  await timeout(new Promise(r => vid.ondurationchange = r), 8000,
+    "durationchange timeout");
+  vid.ondurationchange = unexpected;
+  assert_equals(vid.duration, Infinity, "duration changes to Infinity");
+
+  await timeout(new Promise(r => vid.onresize = r), 8000,
+    "resize timeout");
+  vid.onresize = unexpected;
+  assert_not_equals(vid.videoWidth, 0,
+    "videoWidth is something after \"resize\"");
+  assert_not_equals(vid.videoHeight, 0,
+    "videoHeight is something after \"resize\"");
+
+  await timeout(new Promise(r => vid.onloadedmetadata = r), 8000,
+    "loadedmetadata timeout");
+  vid.onloadedmetadata = unexpected;
+  assert_greater_than_equal(vid.readyState, vid.HAVE_METADATA,
+    "readyState is at least HAVE_METADATA after \"loadedmetadata\"");
+
+  await timeout(new Promise(r => vid.onloadeddata = r), 8000,
+    "loadeddata timeout");
+  vid.onloadeddata = unexpected;
+  assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+    "readyState is HAVE_ENOUGH_DATA after \"loadeddata\" since there's no buffering");
+
+  await timeout(new Promise(r => vid.oncanplay = r), 8000, "canplay timeout");
+  vid.oncanplay = unexpected;
+  assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+    "readyState is HAVE_ENOUGH_DATA after \"canplay\" since there's no buffering");
+
+  await timeout(new Promise(r => vid.oncanplaythrough = r), 8000,
+    "canplaythrough timeout");
+  vid.oncanplaythrough = unexpected;
+  assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+    "readyState is HAVE_ENOUGH_DATA after \"canplaythrough\"");
+
+  // Crank the event loop to see whether any more events are fired.
+  await wait(100);
+}, "Tests that loading a MediaStream in a media element sees all the expected (deterministic) events even when not playing or autoplaying");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html
index 4b9a3c8..3b16006 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html
@@ -22,52 +22,247 @@
 const vid = document.getElementById("vid");
 
 promise_test(async t => {
-  const wait = ms => new Promise(r => t.step_timeout(r, ms));
-  const timeout = (promise, time, msg) =>
-    Promise.race([promise, wait(time).then(() => Promise.reject(new Error(msg)))]);
-
-  const stream = await timeout(navigator.mediaDevices.getUserMedia({video: true}), 10000, "getUserMedia timeout");
-  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
-  vid.defaultPlaybackRate = 0.4;
-  vid.playbackRate = 0.4;
-  vid.preload = "metadata";
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
   vid.srcObject = stream;
-  vid.onratechange = t.unreached_func('ratechange event must not be fired');
-  vid.play();
+}, "Tests that a MediaStream can be assigned to a video element with srcObject");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  vid.srcObject = stream;
+
   assert_true(!vid.seeking, "A MediaStream is not seekable");
   assert_equals(vid.seekable.length, 0, "A MediaStream is not seekable");
+}, "Tests that a MediaStream assigned to a video element is not seekable");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  vid.srcObject = stream;
+
+  assert_equals(vid.readyState, vid.HAVE_NOTHING,
+    "readyState is HAVE_NOTHING initially");
+  await new Promise(r => vid.onloadeddata = r);
+  assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+    "Upon having loaded a media stream, the UA sets readyState to HAVE_ENOUGH_DATA");
+}, "Tests that a MediaStream assigned to a video element is in readyState HAVE_NOTHING initially");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  vid.srcObject = stream;
+
+  assert_equals(vid.duration, NaN,
+    "A MediaStream does not have any duration initially.");
+  await new Promise(r => vid.ondurationchange = r);
+  assert_equals(vid.duration, Infinity,
+    "A loaded MediaStream does not have a pre-defined duration.");
+
+  vid.play();
+  await new Promise(r => vid.ontimeupdate = r);
+  for (const t of stream.getTracks()) {
+    t.stop();
+  }
+
+  await new Promise(r => vid.ondurationchange = r);
+  assert_equals(vid.duration, vid.currentTime,
+    "After ending playback, duration gets set to currentTime");
+}, "Tests that a MediaStream assigned to a video element has expected duration");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+
+  vid.preload = "metadata";
+  vid.srcObject = stream;
+
+  assert_equals(vid.buffered.length, 0,
+    "A MediaStream cannot be preloaded. Therefore, there are no buffered timeranges");
+  assert_equals(vid.preload, "none", "preload must always be none");
+  vid.preload = "auto";
+  assert_equals(vid.preload, "none", "Setting preload must be ignored");
+
+  await new Promise(r => vid.onloadeddata = r);
+  assert_equals(vid.buffered.length, 0,
+    "A MediaStream cannot be preloaded. Therefore, there are no buffered timeranges");
+
+  vid.srcObject = null;
+
+  assert_equals(vid.preload, "metadata",
+    "The preload attribute returns the value it had before using a MediaStream");
+}, "Tests that a video element with a MediaStream assigned is not preloaded");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+
+  vid.defaultPlaybackRate = 0.3;
+  vid.playbackRate = 0.3;
+  vid.onratechange = t.unreached_func("ratechange event must not be fired");
+  vid.srcObject = stream;
+
   assert_equals(vid.defaultPlaybackRate, 1, "playback rate is always 1");
   vid.defaultPlaybackRate = 0.5;
-  assert_equals(vid.defaultPlaybackRate, 1, "Setting defaultPlaybackRate must be ignored");
+  assert_equals(vid.defaultPlaybackRate, 1,
+    "Setting defaultPlaybackRate must be ignored");
+
   assert_equals(vid.playbackRate, 1, "playback rate is always 1");
   vid.playbackRate = 0.5;
   assert_equals(vid.playbackRate, 1, "Setting playbackRate must be ignored");
-  assert_equals(vid.buffered.length, 0, "A MediaStream cannot be preloaded.  Therefore, there is no buffered timeranges");
-  assert_equals(vid.readyState, vid.HAVE_NOTHING, "readyState is HAVE_NOTHING initially");
-  assert_equals(vid.duration, NaN, "A MediaStream does not have any duration initially.");
-  assert_equals(vid.preload, "none", "preload must always be none");
-  vid.preload = "metadata";
-  assert_equals(vid.preload, "none", "Setting preload must be ignored");
 
-  const haveLoadedData = new Promise(r => vid.addEventListener("loadeddata", r, {once: true}));
+  vid.srcObject = null;
+  assert_equals(vid.defaultPlaybackRate, 0.3,
+    "The defaultPlaybackRate attribute returns the value it had before using a MediaStream");
+  assert_equals(vid.playbackRate, 0.3,
+    "The playbackRate attribute is set to the value of the defaultPlaybackRate attribute when unsetting srcObject");
 
-  await new Promise(r => vid.addEventListener("timeupdate", r, {once: true}));
-  assert_equals(vid.played.length, 1, "A MediaStream's timeline always consists of a single range");
-  assert_equals(vid.played.start(0), 0, "A MediaStream's timeline always starts at zero");
-  assert_equals(vid.played.end(0), vid.currentTime, "A MediaStream's end MUST return the last known currentTime, says mediacapture-main");
-  assert_equals(vid.duration, Infinity, "A MediaStream does not have a pre-defined duration. ");
+  // Check that there's no ratechange event
+  await new Promise(r => t.step_timeout(r, 100));
+}, "Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is identical)");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+
+  vid.defaultPlaybackRate = 0.3;
+  vid.playbackRate = 0.4;
+  vid.onratechange = t.unreached_func("ratechange event must not be fired");
+  vid.srcObject = stream;
+
+  assert_equals(vid.defaultPlaybackRate, 1, "playback rate is always 1");
+  vid.defaultPlaybackRate = 0.5;
+  assert_equals(vid.defaultPlaybackRate, 1,
+    "Setting defaultPlaybackRate must be ignored");
+
+  assert_equals(vid.playbackRate, 1, "playback rate is always 1");
+  vid.playbackRate = 0.5;
+  assert_equals(vid.playbackRate, 1, "Setting playbackRate must be ignored");
+
+  vid.srcObject = null;
+  assert_equals(vid.defaultPlaybackRate, 0.3,
+    "The defaultPlaybackRate attribute returns the value it had before using a MediaStream");
+  assert_equals(vid.playbackRate, 0.3,
+    "The playbackRate attribute is set to the value of the defaultPlaybackRate attribute when unsetting srcObject (and fires ratechange)");
+  await new Promise(r => vid.onratechange = r);
+}, "Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is different)");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  vid.srcObject = stream;
+  await new Promise(r => vid.oncanplay = r);
+  vid.play();
+  await new Promise(r => vid.ontimeupdate = r);
+  assert_greater_than(vid.currentTime, 0,
+    "currentTime is greater than 0 after first timeupdate");
+
+  assert_equals(vid.played.length, 1,
+    "A MediaStream's timeline always consists of a single range");
+  assert_equals(vid.played.start(0), 0,
+    "A MediaStream's timeline always starts at zero");
+  assert_equals(vid.played.end(0), vid.currentTime,
+    "A MediaStream's end MUST return the last known currentTime");
 
   const time = vid.currentTime;
   vid.currentTime = 0;
-  assert_equals(vid.currentTime, time, "The UA MUST ignore attempts to set the currentTime attribute");
+  assert_equals(vid.currentTime, time,
+    "The UA MUST ignore attempts to set the currentTime attribute");
+}, "Tests that a media element with an assigned MediaStream reports the played attribute as expected");
 
-  await haveLoadedData;
-  assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA, "Upon having loaded a media stream, the UA sets readyState to HAVE_ENOUGH_DATA");
-  assert_equals(vid.duration, Infinity, "A MediaStream does not have a pre-defined duration.");
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  vid.srcObject = stream;
 
-  // TODO add test that duration must be set to currentTime
-  // when mediastream is destroyed
-}, "Tests that a MediaStream can be assigned to a video element with srcObject");
+  assert_equals(vid.currentTime, 0, "The initial value is 0");
+  vid.currentTime = 42;
+  assert_equals(vid.currentTime, 0,
+    "The UA MUST ignore attempts to set the currentTime attribute (default playback start position)");
+
+  await new Promise(r => vid.onloadeddata = r);
+  assert_equals(vid.currentTime, 0, "The initial value is 0");
+  vid.currentTime = 42;
+  assert_equals(vid.currentTime, 0,
+    "The UA MUST ignore attempts to set the currentTime attribute (official playback position)");
+
+  vid.play();
+  await new Promise(r => vid.ontimeupdate = r);
+  assert_greater_than(vid.currentTime, 0,
+    "currentTime is greater than 0 after first timeupdate");
+
+  const lastTime = vid.currentTime;
+  vid.currentTime = 0;
+  assert_equals(vid.currentTime, lastTime,
+    "The UA MUST ignore attempts to set the currentTime attribute (restart)");
+
+  for(const t of stream.getTracks()) {
+    t.stop();
+  }
+  await new Promise(r => vid.onended = r);
+  assert_greater_than_equal(vid.currentTime, lastTime,
+    "currentTime advanced after stopping");
+}, "Tests that a media element with an assigned MediaStream reports the currentTime attribute as expected");
+
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  assert_equals(vid.loop, false, "loop is false by default");
+  vid.srcObject = stream;
+
+  vid.loop = true;
+  assert_equals(vid.loop, true,
+    "loop can be changed when assigned a MediaStream");
+
+  await new Promise(r => vid.onloadeddata = r);
+  vid.loop = false;
+  assert_equals(vid.loop, false,
+    "loop can be changed when having loaded a MediaStream");
+
+  vid.play();
+  await new Promise(r => vid.ontimeupdate = r);
+  vid.loop = true;
+  assert_equals(vid.loop, true,
+    "loop can be changed when playing a MediaStream");
+
+  for(const t of stream.getTracks()) {
+    t.stop();
+  }
+  // If loop is ignored, we get "ended",
+  // otherwise the media element sets currentTime to 0 without ending.
+  await new Promise(r => vid.onended = r);
+}, "Tests that the loop attribute has no effect on a media element with an assigned MediaStream");
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/svg/text/reftests/text-xml-space-001-ref.svg b/third_party/blink/web_tests/external/wpt/svg/text/reftests/text-xml-space-001-ref.svg
new file mode 100644
index 0000000..1572149
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/text/reftests/text-xml-space-001-ref.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml">
+  <title>SVG Reference</title>
+  <text x="50" y="50" font-family="monospace">Some&#160;&#160;Text</text>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/svg/text/reftests/text-xml-space-001.svg b/third_party/blink/web_tests/external/wpt/svg/text/reftests/text-xml-space-001.svg
new file mode 100644
index 0000000..c58bd9d4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/text/reftests/text-xml-space-001.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml">
+  <title>SVG Test: Behavior of xml:space="preserve"</title>
+  <h:link rel="help" href="https://svgwg.org/svg2-draft/styling.html#UAStyleSheet"/>
+  <h:link rel="match" href="text-xml-space-001-ref.svg"/>
+  <g xml:space="preserve">
+    <text x="50" y="50" font-family="monospace">Some  Text</text>
+  </g>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/META.yml b/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/META.yml
new file mode 100644
index 0000000..c09a6e0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/META.yml
@@ -0,0 +1,6 @@
+spec: https://w3c.github.io/navigation-timing/
+suggested_reviewers:
+  - plehegar
+  - igrigorik
+  - toddreifsteck
+  - yoavweiss
diff --git a/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/registry.any.js b/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/registry.any.js
new file mode 100644
index 0000000..4db249b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/registry.any.js
@@ -0,0 +1,25 @@
+// META: script=resources/utils.js
+
+test(() => {
+  assert_true(!!self.PerformanceObserver, "PerformanceObserver");
+  assert_true(!!self.PerformanceObserver.supportedEntryTypes,
+              "PerformanceObserver.supportedEntryTypes");
+}, "PerformanceObserver.supportedEntryTypes exists");
+
+// UPDATE HERE if new entry
+[
+  [ "mark", "PerformanceMark" ],
+  [ "measure", "PerformanceMeasure" ],
+  [ "resource", "PerformanceResourceTiming" ],
+].forEach(test_support);
+
+// UPDATE BELOW to ensure the entry gets created
+
+// mark
+self.performance.mark('mymark');
+
+// measure
+self.performance.measure('mymeasure');
+
+// resource
+fetch(self.location.href + "?" + Math.random());
diff --git a/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/registry.window.js b/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/registry.window.js
new file mode 100644
index 0000000..21ef2230
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/registry.window.js
@@ -0,0 +1,33 @@
+// META: script=resources/utils.js
+
+test(() => {
+  assert_true(!!self.PerformanceObserver, "PerformanceObserver");
+  assert_true(!!self.PerformanceObserver.supportedEntryTypes,
+              "PerformanceObserver.supportedEntryTypes");
+}, "PerformanceObserver.supportedEntryTypes exists");
+
+// UPDATE HERE if new entry
+[
+  [ "navigation", "PerformanceNavigationTiming" ],
+  [ "paint", "PerformancePaintTiming" ],
+  [ "longtask", "PerformanceLongTaskTiming" ],
+].forEach(test_support);
+
+// UPDATE BELOW to ensure the entry gets created
+
+// paint
+if (self.document) document.head.parentNode.appendChild(document.createTextNode('text inserted on purpose'));
+
+// longtask
+function syncWait(waitDuration) {
+  if (waitDuration <= 0)
+    return;
+
+  const startTime = performance.now();
+  let unused = '';
+  for (let i = 0; i < 10000; i++)
+    unused += '' + Math.random();
+
+  return syncWait(waitDuration - (performance.now() - startTime));
+}
+syncWait(50);
diff --git a/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/resources/utils.js b/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/resources/utils.js
new file mode 100644
index 0000000..0ec9605
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/resources/utils.js
@@ -0,0 +1,29 @@
+const STEPS = {};
+
+const types = (self.PerformanceObserver
+                  && self.PerformanceObserver.supportedEntryTypes)?
+    self.PerformanceObserver.supportedEntryTypes
+    : undefined;
+
+if (types) {
+  // we observe everything as soon as possible
+  new PerformanceObserver(function (list, observer) {
+    for (const entry of list.getEntries())
+      if (STEPS[entry.entryType]) STEPS[entry.entryType](entry);
+  }).observe({entryTypes: self.PerformanceObserver.supportedEntryTypes});
+}
+
+function test_support(def) {
+  if (!types || !types.includes(def[0])) {
+    return;
+  }
+  const desc = `'${def[0]}' entries should be observable`;
+  const t = async_test(desc);
+
+  STEPS[def[0]] = (entry) => {
+    t.step(() => assert_equals(Object.prototype.toString.call(entry),
+    `[object ${def[1]}]`,
+    `Class name of entry should be ${def[1]}.`));
+    t.done();
+  }
+}
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/idlharness.https.window-expected.txt
index 4b697a3d..da18d84 100644
--- a/third_party/blink/web_tests/external/wpt/web-nfc/idlharness.https.window-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/web-nfc/idlharness.https.window-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
+Found 50 tests; 1 PASS, 49 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 FAIL NFCWriter interface: existence and properties of interface object assert_own_property: self does not have own property "NFCWriter" expected property "NFCWriter" missing
 FAIL NFCWriter interface object length assert_own_property: self does not have own property "NFCWriter" expected property "NFCWriter" missing
@@ -33,9 +34,11 @@
 FAIL NFCReadingEvent interface: existence and properties of interface prototype object assert_own_property: self does not have own property "NFCReadingEvent" expected property "NFCReadingEvent" missing
 FAIL NFCReadingEvent interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "NFCReadingEvent" expected property "NFCReadingEvent" missing
 FAIL NFCReadingEvent interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "NFCReadingEvent" expected property "NFCReadingEvent" missing
+FAIL NFCReadingEvent interface: attribute serialNumber assert_own_property: self does not have own property "NFCReadingEvent" expected property "NFCReadingEvent" missing
 FAIL NFCReadingEvent interface: attribute message assert_own_property: self does not have own property "NFCReadingEvent" expected property "NFCReadingEvent" missing
 FAIL NFCReadingEvent must be primary interface of new NFCReadingEvent("reading", { message: {"url":"/custom/path","records":[{"recordType":"text","data":"Hello World"}]} }) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: NFCReadingEvent is not defined"
 FAIL Stringification of new NFCReadingEvent("reading", { message: {"url":"/custom/path","records":[{"recordType":"text","data":"Hello World"}]} }) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: NFCReadingEvent is not defined"
+FAIL NFCReadingEvent interface: new NFCReadingEvent("reading", { message: {"url":"/custom/path","records":[{"recordType":"text","data":"Hello World"}]} }) must inherit property "serialNumber" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: NFCReadingEvent is not defined"
 FAIL NFCReadingEvent interface: new NFCReadingEvent("reading", { message: {"url":"/custom/path","records":[{"recordType":"text","data":"Hello World"}]} }) must inherit property "message" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: NFCReadingEvent is not defined"
 FAIL NFCErrorEvent interface: existence and properties of interface object assert_own_property: self does not have own property "NFCErrorEvent" expected property "NFCErrorEvent" missing
 FAIL NFCErrorEvent interface object length assert_own_property: self does not have own property "NFCErrorEvent" expected property "NFCErrorEvent" missing
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js
index d859ac7..6a4ce85 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-helper.js
@@ -254,6 +254,9 @@
 // This should work for RTCSctpTransport, RTCDtlsTransport and RTCIceTransport.
 function waitForState(transport, state) {
   return new Promise((resolve, reject) => {
+    if (transport.state == state) {
+      resolve();
+    }
     const eventHandler = () => {
       if (transport.state == state) {
         transport.removeEventListener('statechange', eventHandler, false);
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https.html
index 6d4ab50..385bb517 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https.html
@@ -276,5 +276,42 @@
 
       closed
         The RTCIceTransport has shut down and is no longer responding to STUN requests.
-   */
+  */
+
+for (let bundle_policy of ['balanced', 'max-bundle', 'max-compat']) {
+
+
+    promise_test(async t => {
+      const caller = new RTCPeerConnection({bundlePolicy: bundle_policy});
+      t.add_cleanup(() => caller.close());
+      const stream = await navigator.mediaDevices.getUserMedia(
+          {audio: true, video:true});
+      t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+      const [track1, track2] = stream.getTracks();
+      const sender1 = caller.addTrack(track1);
+      const sender2 = caller.addTrack(track2);
+      caller.createDataChannel('datachannel');
+      const callee = new RTCPeerConnection();
+      t.add_cleanup(() => callee.close());
+      coupleIceCandidates(caller, callee);
+      const offer = await caller.createOffer();
+      await caller.setLocalDescription(offer);
+      const [caller_transceiver1, caller_transceiver2] = caller.getTransceivers();
+      assert_equals(sender1.transport, caller_transceiver1.sender.transport);
+      await callee.setRemoteDescription(offer);
+      const [callee_transceiver1, callee_transceiver2] = callee.getTransceivers();
+      const answer = await callee.createAnswer();
+      await callee.setLocalDescription(answer);
+      await caller.setRemoteDescription(answer);
+      // At this point, we should have a single ICE transport, and it
+      // should eventually get to the "connected" state.
+      await waitForState(caller_transceiver1.receiver.transport.iceTransport,
+                         'connected');
+      // The PeerConnection's iceConnectionState should therefore be 'connected'
+      assert_equals(caller.iceConnectionState, 'connected',
+                    'PC.iceConnectionState:');
+    }, 'iceConnectionState changes at the right time, with bundle policy ' +
+                 bundle_policy);
+  }
+
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt
new file mode 100644
index 0000000..9d294da
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt
@@ -0,0 +1,80 @@
+This is a testharness.js-based test.
+Found 76 tests; 48 PASS, 28 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS getStats succeeds
+PASS RTCRtpStreamStats's ssrc
+PASS RTCRtpStreamStats's kind
+PASS RTCRtpStreamStats's transportId
+PASS RTCRtpStreamStats's codecId
+PASS RTCReceivedRtpStreamStats's packetsReceived
+PASS RTCReceivedRtpStreamStats's packetsLost
+PASS RTCReceivedRtpStreamStats's jitter
+FAIL RTCReceivedRtpStreamStats's packetsDiscarded assert_true: Is packetsDiscarded present expected true got false
+PASS RTCInboundRtpStreamStats's trackId
+FAIL RTCInboundRtpStreamStats's receiverId assert_true: Is receiverId present expected true got false
+FAIL RTCInboundRtpStreamStats's remoteId assert_true: Is remoteId present expected true got false
+PASS RTCInboundRtpStreamStats's framesDecoded
+PASS RTCRemoteInboundRtpStreamStats's localId
+PASS RTCRemoteInboundRtpStreamStats's roundTripTime
+PASS RTCSentRtpStreamStats's packetsSent
+PASS RTCSentRtpStreamStats's bytesSent
+PASS RTCOutboundRtpStreamStats's trackId
+FAIL RTCOutboundRtpStreamStats's senderId assert_true: Is senderId present expected true got false
+FAIL RTCOutboundRtpStreamStats's remoteId assert_true: Is remoteId present expected true got false
+PASS RTCOutboundRtpStreamStats's framesEncoded
+FAIL RTCRemoteOutboundRtpStreamStats's localId assert_true: Is localId present expected true got false
+FAIL RTCRemoteOutboundRtpStreamStats's remoteTimestamp assert_true: Is remoteTimestamp present expected true got false
+PASS RTCPeerConnectionStats's dataChannelsOpened
+PASS RTCPeerConnectionStats's dataChannelsClosed
+PASS RTCDataChannelStats's protocol
+FAIL RTCDataChannelStats's dataChannelIdentifier assert_true: Is dataChannelIdentifier present expected true got false
+PASS RTCDataChannelStats's state
+PASS RTCDataChannelStats's messagesSent
+PASS RTCDataChannelStats's bytesSent
+PASS RTCDataChannelStats's messagesReceived
+PASS RTCDataChannelStats's bytesReceived
+FAIL RTCMediaStreamStats's streamIdentifer assert_true: Is streamIdentifer present expected true got false
+PASS RTCMediaStreamStats's trackIds
+FAIL RTCMediaHandlerStats's trackIdentifier assert_true: Is trackIdentifier present expected true got false
+FAIL RTCMediaHandlerStats's remoteSource assert_true: Is remoteSource present expected true got false
+FAIL RTCMediaHandlerStats's ended assert_true: Is ended present expected true got false
+FAIL RTCAudioHandlerStats's audioLevel assert_true: Is audioLevel present expected true got false
+FAIL RTCVideoHandlerStats's frameWidth assert_true: Is frameWidth present expected true got false
+FAIL RTCVideoHandlerStats's frameHeight assert_true: Is frameHeight present expected true got false
+FAIL RTCVideoHandlerStats's framesPerSecond assert_true: Is framesPerSecond present expected true got false
+FAIL RTCVideoSenderStats's framesSent assert_true: Is framesSent present expected true got false
+FAIL RTCVideoReceiverStats's framesReceived assert_true: Is framesReceived present expected true got false
+FAIL RTCVideoReceiverStats's framesDecoded assert_true: Is framesDecoded present expected true got false
+FAIL RTCVideoReceiverStats's framesDropped assert_true: Is framesDropped present expected true got false
+FAIL RTCVideoReceiverStats's partialFramesLost assert_true: Is partialFramesLost present expected true got false
+PASS RTCCodecStats's payloadType
+FAIL RTCCodecStats's codecType assert_true: Is codecType present expected true got false
+PASS RTCCodecStats's clockRate
+FAIL RTCCodecStats's channels assert_true: Is channels present expected true got false
+FAIL RTCCodecStats's sdpFmtpLine assert_true: Is sdpFmtpLine present expected true got false
+PASS RTCTransportStats's bytesSent
+PASS RTCTransportStats's bytesReceived
+FAIL RTCTransportStats's rtcpTransportStatsId assert_true: Is rtcpTransportStatsId present expected true got false
+PASS RTCTransportStats's selectedCandidatePairId
+PASS RTCTransportStats's localCertificateId
+PASS RTCTransportStats's remoteCertificateId
+PASS RTCIceCandidatePairStats's transportId
+PASS RTCIceCandidatePairStats's localCandidateId
+PASS RTCIceCandidatePairStats's remoteCandidateId
+PASS RTCIceCandidatePairStats's state
+PASS RTCIceCandidatePairStats's priority
+PASS RTCIceCandidatePairStats's nominated
+PASS RTCIceCandidatePairStats's bytesSent
+PASS RTCIceCandidatePairStats's bytesReceived
+PASS RTCIceCandidatePairStats's totalRoundTripTime
+PASS RTCIceCandidatePairStats's currentRoundTripTime
+FAIL RTCIceCandidateStats's address assert_true: Is address present expected true got false
+PASS RTCIceCandidateStats's port
+PASS RTCIceCandidateStats's protocol
+PASS RTCIceCandidateStats's candidateType
+FAIL RTCIceCandidateStats's url assert_true: Is url present expected true got false
+PASS RTCCertificateStats's fingerprint
+PASS RTCCertificateStats's fingerprintAlgorithm
+PASS RTCCertificateStats's base64Certificate
+FAIL RTCCertificateStats's issuerCertificateId assert_true: Is issuerCertificateId present expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https.html
new file mode 100644
index 0000000..fd8c74b9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https.html
@@ -0,0 +1,266 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>Mandatory-to-implement stats compliance (a subset of webrtc-stats)</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="RTCPeerConnection-helper.js"></script>
+<script src="dictionary-helper.js"></script>
+<script src="RTCStats-helper.js"></script>
+<script>
+'use strict';
+
+// From https://w3c.github.io/webrtc-pc/#mandatory-to-implement-stats
+
+const mandatory = {
+  RTCRtpStreamStats: [
+    "ssrc",
+    "kind",
+    "transportId",
+    "codecId",
+  ],
+  RTCReceivedRtpStreamStats: [
+    "packetsReceived",
+    "packetsLost",
+    "jitter",
+    "packetsDiscarded",
+  ],
+  RTCInboundRtpStreamStats: [
+    "trackId",
+    "receiverId",
+    "remoteId",
+    "framesDecoded",
+  ],
+  RTCRemoteInboundRtpStreamStats: [
+    "localId",
+    "roundTripTime",
+  ],
+  RTCSentRtpStreamStats: [
+    "packetsSent",
+    "bytesSent"
+  ],
+  RTCOutboundRtpStreamStats: [
+    "trackId",
+    "senderId",
+    "remoteId",
+    "framesEncoded",
+  ],
+  RTCRemoteOutboundRtpStreamStats: [
+    "localId",
+    "remoteTimestamp",
+  ],
+  RTCPeerConnectionStats: [
+    "dataChannelsOpened",
+    "dataChannelsClosed",
+  ],
+  RTCDataChannelStats: [
+    "protocol",
+    "dataChannelIdentifier",
+    "state",
+    "messagesSent",
+    "bytesSent",
+    "messagesReceived",
+    "bytesReceived",
+  ],
+  RTCMediaStreamStats: [
+    "streamIdentifer",
+    "trackIds",
+  ],
+  RTCMediaHandlerStats: [
+    "trackIdentifier",
+    "remoteSource",
+    "ended",
+  ],
+  RTCAudioHandlerStats: [
+    "audioLevel",
+  ],
+  RTCVideoHandlerStats: [
+    "frameWidth",
+    "frameHeight",
+    "framesPerSecond",
+  ],
+  RTCVideoSenderStats: [
+    "framesSent",
+  ],
+  RTCVideoReceiverStats: [
+    "framesReceived",
+    "framesDecoded",
+    "framesDropped",
+    "partialFramesLost",
+  ],
+  RTCCodecStats: [
+    "payloadType",
+    "codecType",
+    "clockRate",
+    "channels",
+    "sdpFmtpLine",
+  ],
+  RTCTransportStats: [
+    "bytesSent",
+    "bytesReceived",
+    "rtcpTransportStatsId",
+    "selectedCandidatePairId",
+    "localCertificateId",
+    "remoteCertificateId",
+  ],
+  RTCIceCandidatePairStats: [
+    "transportId",
+    "localCandidateId",
+    "remoteCandidateId",
+    "state",
+    "priority",
+    "nominated",
+    "bytesSent",
+    "bytesReceived",
+    "totalRoundTripTime",
+    "currentRoundTripTime",
+  ],
+  RTCIceCandidateStats: [
+    "address",
+    "port",
+    "protocol",
+    "candidateType",
+    "url",
+  ],
+  RTCCertificateStats: [
+    "fingerprint",
+    "fingerprintAlgorithm",
+    "base64Certificate",
+    "issuerCertificateId",
+  ],
+};
+
+// From https://w3c.github.io/webrtc-stats/webrtc-stats.html#rtcstatstype-str*
+
+const dictionaryNames = {
+  "codec": "RTCCodecStats",
+  "inbound-rtp": "RTCInboundRtpStreamStats",
+  "outbound-rtp": "RTCOutboundRtpStreamStats",
+  "remote-inbound-rtp": "RTCRemoteInboundRtpStreamStats",
+  "remote-outbound-rtp": "RTCRemoteOutboundRtpStreamStats",
+  "csrc": "RTCRtpContributingSourceStats",
+  "peer-connection": "RTCPeerConnectionStats",
+  "data-channel": "RTCDataChannelStats",
+  "stream": "RTCMediaStreamStats",
+  "track": {
+    video: "RTCSenderVideoTrackAttachmentStats",
+    audio: "RTCSenderAudioTrackAttachmentStats"
+  },
+  "sender": {
+    audio: "RTCAudioSenderStats",
+    video: "RTCVideoSenderStats"
+  },
+  "receiver": {
+    audio: "RTCAudioReceiverStats",
+    video: "RTCVideoReceiverStats",
+  },
+  "transport": "RTCTransportStats",
+  "candidate-pair": "RTCIceCandidatePairStats",
+  "local-candidate": "RTCIceCandidateStats",
+  "remote-candidate": "RTCIceCandidateStats",
+  "certificate": "RTCCertificateStats",
+};
+
+// From https://w3c.github.io/webrtc-stats/webrtc-stats.html (webidl)
+
+const parents = {
+  RTCVideoHandlerStats: "RTCMediaHandlerStats",
+  RTCVideoSenderStats: "RTCVideoHandlerStats",
+  RTCSenderVideoTrackAttachmentStats: "RTCVideoSenderStats",
+  RTCVideoReceiverStats: "RTCVideoHandlerStats",
+  RTCAudioHandlerStats: "RTCMediaHandlerStats",
+  RTCAudioSenderStats: "RTCAudioHandlerStats",
+  RTCSenderAudioTrackAttachmentStats: "RTCAudioSenderStats",
+  RTCAudioReceiverStats: "RTCAudioHandlerStats",
+  RTCReceivedRtpStreamStats: "RTCRtpStreamStats",
+  RTCInboundRtpStreamStats: "RTCReceivedRtpStreamStats",
+  RTCRemoteInboundRtpStreamStats: "RTCReceivedRtpStreamStats",
+  RTCSentRtpStreamStats: "RTCRtpStreamStats",
+  RTCOutboundRtpStreamStats: "RTCSentRtpStreamStats",
+  RTCRemoteOutboundRtpStreamStats : "RTCSentRtpStreamStats",
+};
+
+const remaining = JSON.parse(JSON.stringify(mandatory));
+for (const dictName in remaining) {
+  remaining[dictName] = new Set(remaining[dictName]);
+}
+
+async function getAllStats(t, pc) {
+  // Try to obtain as many stats as possible, waiting up to 20 seconds for
+  // roundTripTime which can take several RTCP messages to calculate.
+  let stats;
+  for (let i = 0; i < 20; i++) {
+    stats = await pc.getStats();
+    const values = [...stats.values()];
+    const [audio, video] = ["audio", "video"].map(kind =>
+      values.find(s => s.type == "remote-inbound-rtp" && s.kind == kind));
+    if (audio && "roundTripTime" in audio &&
+        video && "roundTripTime" in video) {
+      return stats;
+    }
+    await new Promise(r => t.step_timeout(r, 1000));
+  }
+  return stats;
+}
+
+let succeed;
+const success = new Promise(r => succeed = r);
+
+promise_test(async t => {
+  const pc1 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+  const pc2 = new RTCPeerConnection();
+  t.add_cleanup(() => pc2.close());
+
+  pc1.createDataChannel("dummy", {negotiated: true, id: 0});
+  pc2.createDataChannel("dummy", {negotiated: true, id: 0});
+  const stream = await getNoiseStream({video: true, audio:true});
+  for (const track of stream.getTracks()) {
+    pc1.addTrack(track, stream);
+    pc2.addTrack(track, stream);
+    t.add_cleanup(() => track.stop());
+  }
+  exchangeIceCandidates(pc1, pc2);
+  await doSignalingHandshake(pc1, pc2);
+  const stats = await getAllStats(t, pc1);
+
+  // The focus of this test is not API correctness, but rather to provide an
+  // accessible metric of implementation progress by dictionary member. We count
+  // whether we've seen each dictionary's mandatory members in getStats().
+
+  for (const stat of stats.values()) {
+    let dictName = dictionaryNames[stat.type];
+    if (!dictName) continue;
+    if (typeof dictName == "object") {
+      dictName = dictName[stat.kind];
+    }
+    assert_equals(typeof dictName, "string", "Test error. String.");
+    if (dictName && mandatory[dictName]) {
+      do {
+        const memberNames = mandatory[dictName];
+        const remainingNames = remaining[dictName];
+        assert_true(memberNames.length > 0, "Test error. Parent not found.");
+        for (const memberName of memberNames) {
+          if (memberName in stat) {
+            assert_not_equals(stat[memberName], undefined, "Not undefined");
+            remainingNames.delete(memberName);
+          }
+        }
+        dictName = parents[dictName];
+      } while (dictName);
+    }
+  }
+  succeed();
+}, 'getStats succeeds');
+
+for (const dictName in mandatory) {
+  for (const memberName of mandatory[dictName]) {
+    promise_test(async t => {
+      await success;
+      assert_true(!remaining[dictName].has(memberName),
+                  `Is ${memberName} present`);
+    }, `${dictName}'s ${memberName}`);
+  }
+}
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/protocol/candidate-exchange.https.html b/third_party/blink/web_tests/external/wpt/webrtc/protocol/candidate-exchange.https.html
index 2603a02c..d1bc3581 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/protocol/candidate-exchange.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/protocol/candidate-exchange.https.html
@@ -26,15 +26,36 @@
   return waiter;
 }
 
+class StateLogger {
+  constructor(source, eventname, field) {
+    source.addEventListener(eventname, event => {
+      this.events.push(source[field]);
+    });
+    this.events = [source[field]];
+  }
+}
+
+class IceStateLogger extends StateLogger {
+  constructor(source) {
+    super(source, 'iceconnectionstatechange', 'iceConnectionState');
+  }
+}
+
 promise_test(async t => {
   const pc1 = new RTCPeerConnection();
   const pc2 = new RTCPeerConnection();
   t.add_cleanup(() => pc1.close());
   t.add_cleanup(() => pc2.close());
   pc1.createDataChannel('datachannel');
+  pc1IceStates = new IceStateLogger(pc1);
+  pc2IceStates = new IceStateLogger(pc1);
   coupleIceCandidates(pc1, pc2);
   await doSignalingHandshake(pc1, pc2);
-  await waitForIceStateChange(pc1, ['connected', 'completed']);
+  // Note - it's been claimed that this state sometimes jumps straight
+  // to "completed". If so, this test should be flaky.
+  await waitForIceStateChange(pc1, ['connected']);
+  assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
+  assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
 }, 'Two way ICE exchange works');
 
 promise_test(async t => {
@@ -42,6 +63,8 @@
   const pc2 = new RTCPeerConnection();
   t.add_cleanup(() => pc1.close());
   t.add_cleanup(() => pc2.close());
+  pc1IceStates = new IceStateLogger(pc1);
+  pc2IceStates = new IceStateLogger(pc1);
   let candidates = [];
   pc1.createDataChannel('datachannel');
   pc1.onicecandidate = e => {
@@ -62,6 +85,8 @@
   const candidate_pair = pc1.sctp.transport.iceTransport.getSelectedCandidatePair();
   assert_equals(candidate_pair.local.type, 'host');
   assert_equals(candidate_pair.remote.type, 'prflx');
+  assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
+  assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
 }, 'Adding only caller -> callee candidates gives a connection');
 
 promise_test(async t => {
@@ -69,6 +94,8 @@
   const pc2 = new RTCPeerConnection();
   t.add_cleanup(() => pc1.close());
   t.add_cleanup(() => pc2.close());
+  pc1IceStates = new IceStateLogger(pc1);
+  pc2IceStates = new IceStateLogger(pc1);
   let candidates = [];
   pc1.createDataChannel('datachannel');
   pc2.onicecandidate = e => {
@@ -89,8 +116,92 @@
   const candidate_pair = pc2.sctp.transport.iceTransport.getSelectedCandidatePair();
   assert_equals(candidate_pair.local.type, 'host');
   assert_equals(candidate_pair.remote.type, 'prflx');
+  assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
+  assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
 }, 'Adding only callee -> caller candidates gives a connection');
 
+promise_test(async t => {
+  const pc1 = new RTCPeerConnection();
+  const pc2 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+  t.add_cleanup(() => pc2.close());
+  pc1IceStates = new IceStateLogger(pc1);
+  pc2IceStates = new IceStateLogger(pc1);
+  let pc2ToPc1Candidates = [];
+  pc1.createDataChannel('datachannel');
+  pc2.onicecandidate = e => {
+    pc2ToPc1Candidates.push(e.candidate);
+    // This particular test verifies that candidates work
+    // properly if added from the pc2 onicecandidate event.
+    if (!e.candidate) {
+      for (const candidate of pc2ToPc1Candidates) {
+        if (candidate) {
+          pc1.addIceCandidate(candidate);
+        }
+      }
+    }
+  }
+  // Candidates from |pc1| are not delivered to |pc2|. |pc2| will use
+  // peer-reflexive candidates.
+  await doSignalingHandshake(pc1, pc2);
+  await Promise.all([waitForIceStateChange(pc1, ['connected', 'completed']),
+                     waitForIceStateChange(pc2, ['connected', 'completed'])]);
+  const candidate_pair = pc2.sctp.transport.iceTransport.getSelectedCandidatePair();
+  assert_equals(candidate_pair.local.type, 'host');
+  assert_equals(candidate_pair.remote.type, 'prflx');
+  assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
+  assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
+}, 'Adding callee -> caller candidates from end-of-candidates gives a connection');
+
+promise_test(async t => {
+  const pc1 = new RTCPeerConnection();
+  const pc2 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+  t.add_cleanup(() => pc2.close());
+  pc1IceStates = new IceStateLogger(pc1);
+  pc2IceStates = new IceStateLogger(pc1);
+  let pc1ToPc2Candidates = [];
+  let pc2ToPc1Candidates = [];
+  pc1.createDataChannel('datachannel');
+  pc1.onicecandidate = e => {
+    pc1ToPc2Candidates.push(e.candidate);
+  }
+  pc2.onicecandidate = e => {
+    pc2ToPc1Candidates.push(e.candidate);
+  }
+  const offer = await pc1.createOffer();
+  await Promise.all([pc1.setLocalDescription(offer),
+                     pc2.setRemoteDescription(offer)]);
+  const answer = await pc2.createAnswer();
+  await iceGatheringCompleteWaiter(pc1);
+  await pc2.setLocalDescription(answer).then(() => {
+    for (const candidate of pc1ToPc2Candidates) {
+      if (candidate) {
+        pc2.addIceCandidate(candidate);
+      }
+    }
+  });
+  await iceGatheringCompleteWaiter(pc2);
+  pc1.setRemoteDescription(answer).then(async () => {
+    for (const candidate of pc2ToPc1Candidates) {
+      if (candidate) {
+        await pc1.addIceCandidate(candidate);
+      }
+    }
+  });
+  await Promise.all([waitForIceStateChange(pc1, ['connected', 'completed']),
+                     waitForIceStateChange(pc2, ['connected', 'completed'])]);
+  const candidate_pair =
+        pc1.sctp.transport.iceTransport.getSelectedCandidatePair();
+  assert_equals(candidate_pair.local.type, 'host');
+  // When we supply remote candidates, we expect a jump to the 'host' candidate,
+  // but it might also remain as 'prflx'.
+  assert_true(candidate_pair.remote.type == 'host' ||
+              candidate_pair.remote.type == 'prflx');
+  assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
+  assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
+}, 'Explicit offer/answer exchange gives a connection');
+
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/workers/Worker-nested-importScripts-error.html b/third_party/blink/web_tests/external/wpt/workers/Worker-nested-importScripts-error.html
index 8863b752..bd96c835 100644
--- a/third_party/blink/web_tests/external/wpt/workers/Worker-nested-importScripts-error.html
+++ b/third_party/blink/web_tests/external/wpt/workers/Worker-nested-importScripts-error.html
@@ -12,6 +12,7 @@
   }).then(e => {
     assert_equals(e.type, "error");
     assert_true(e.filename.indexOf('invalidScript.js') >= 0);
+    e.preventDefault();
   });
 }, 'Tests that errors from the import scripts come from the expected file.')
 </script>
diff --git a/third_party/blink/web_tests/http/tests/csspaint/entire-canvas-visible-zoom-expected.html b/third_party/blink/web_tests/http/tests/csspaint/entire-canvas-visible-zoom-expected.html
new file mode 100644
index 0000000..4686a9b
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/csspaint/entire-canvas-visible-zoom-expected.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<style>
+html, body { margin: 0; padding: 0; }
+</style>
+<body>
+<div>
+<canvas id="output" width="100" height="100"></canvas>
+</div>
+<script>
+var canvas = document.getElementById('output');
+var ctx = canvas.getContext('2d');
+ctx.fillStyle = 'green';
+ctx.fillRect(0, 0, 10, 10);
+ctx.fillRect(90, 0, 10, 10);
+ctx.fillRect(0, 90, 10, 10);
+ctx.fillRect(90, 90, 10, 10);
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/http/tests/csspaint/entire-canvas-visible-zoom.html b/third_party/blink/web_tests/http/tests/csspaint/entire-canvas-visible-zoom.html
new file mode 100644
index 0000000..d92da1ad
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/csspaint/entire-canvas-visible-zoom.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<script src="./resources/test-runner-paint-worklet.js"></script>
+<style>
+html, body { margin: 0; padding: 0; }
+#output {
+    width: 200px;
+    height: 200px;
+    background-image: paint(worklet);
+}
+</style>
+<body>
+<div id="output"></div>
+
+<script id="code" type="text/worklet">
+registerPaint('worklet', class {
+    paint(ctx, geom) {
+        ctx.fillStyle = 'green';
+        ctx.fillRect(0, 0, 20, 20);
+        ctx.fillRect(180, 0, 20, 20);
+        ctx.fillRect(0, 180, 20, 20);
+        ctx.fillRect(180, 180, 20, 20);
+    }
+});
+</script>
+
+<script>
+    document.body.style.zoom = "50%";
+    importPaintWorkletThenEndTest(document.getElementById('code').textContent);
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
deleted file mode 100644
index 0065caa8..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
deleted file mode 100644
index df68f6bb2..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
deleted file mode 100644
index 7c6d7e50..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/html/cross-origin/anonymous.tentative-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/html/cross-origin/anonymous.tentative-expected.txt
new file mode 100644
index 0000000..9e6555e
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/html/cross-origin/anonymous.tentative-expected.txt
@@ -0,0 +1,13 @@
+This is a testharness.js-based test.
+FAIL Top-level with anonymous policy: navigating a frame to a null policy should fail. assert_equals: expected null but got Document node with 1 child
+FAIL Top-level with anonymous policy: navigating a frame from an anonymous policy to a null policy should fail. assert_equals: Navigation to null policy should fail expected null but got Document node with 1 child
+FAIL Top-level with anonymous policy: navigating a frame from a use-credentials policy to a null policy should fail. assert_equals: Navigation to null policy should fail expected null but got Document node with 1 child
+PASS Top-level with anonymous policy: creating a noopener popup with null policy should work.
+PASS Top-level with anonymous policy: creating a popup with null policy should fail.
+PASS Top-level noopener with anonymous policy: navigating to a different policy should work
+FAIL Fetch policy: anonymous policy no-cors fetches should be changed to cors assert_equals: type should have been changed to cors expected "cors" but got "opaque"
+PASS Top-level popup with anonymous policy: Navigating the popup to a null policy should fail.
+PASS Top-level popup with anonymous policy: Navigating the popup to a null policy should fail. (even when we clear the opener)
+PASS Top-level popup with anonymous policy: Navigating the popup to a null policy should fail. (even opener window is closed)
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
deleted file mode 100644
index 7c6d7e50..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
deleted file mode 100644
index 0e4a982..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
deleted file mode 100644
index e69de29..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
+++ /dev/null
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
deleted file mode 100644
index e69de29..0000000
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
+++ /dev/null
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
deleted file mode 100644
index 0e4a982..0000000
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png b/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
deleted file mode 100644
index e69de29..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
+++ /dev/null
diff --git a/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png b/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
deleted file mode 100644
index e69de29..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
+++ /dev/null
diff --git a/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.txt
deleted file mode 100644
index 5a6ac0b..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Content-Type: text/plain
-#EOF
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/cross-origin/anonymous.tentative-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/html/cross-origin/anonymous.tentative-expected.txt
new file mode 100644
index 0000000..9e6555e
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/external/wpt/html/cross-origin/anonymous.tentative-expected.txt
@@ -0,0 +1,13 @@
+This is a testharness.js-based test.
+FAIL Top-level with anonymous policy: navigating a frame to a null policy should fail. assert_equals: expected null but got Document node with 1 child
+FAIL Top-level with anonymous policy: navigating a frame from an anonymous policy to a null policy should fail. assert_equals: Navigation to null policy should fail expected null but got Document node with 1 child
+FAIL Top-level with anonymous policy: navigating a frame from a use-credentials policy to a null policy should fail. assert_equals: Navigation to null policy should fail expected null but got Document node with 1 child
+PASS Top-level with anonymous policy: creating a noopener popup with null policy should work.
+PASS Top-level with anonymous policy: creating a popup with null policy should fail.
+PASS Top-level noopener with anonymous policy: navigating to a different policy should work
+FAIL Fetch policy: anonymous policy no-cors fetches should be changed to cors assert_equals: type should have been changed to cors expected "cors" but got "opaque"
+PASS Top-level popup with anonymous policy: Navigating the popup to a null policy should fail.
+PASS Top-level popup with anonymous policy: Navigating the popup to a null policy should fail. (even when we clear the opener)
+PASS Top-level popup with anonymous policy: Navigating the popup to a null policy should fail. (even opener window is closed)
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
deleted file mode 100644
index 27727867..0000000
--- a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
deleted file mode 100644
index 97c30c1..0000000
--- a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png b/third_party/blink/web_tests/platform/win7/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
deleted file mode 100644
index 27727867..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png b/third_party/blink/web_tests/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
deleted file mode 100644
index 0065caa8..0000000
--- a/third_party/blink/web_tests/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https-expected.txt
index b9fe8a5..552da96b 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https-expected.txt
@@ -6,5 +6,8 @@
 PASS connection with audio track should eventually have connected connection state
 PASS connection with audio and video tracks should eventually have connected connection state
 FAIL ICE can connect in a recvonly usecase promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
+FAIL iceConnectionState changes at the right time, with bundle policy balanced promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'sender' of undefined"
+FAIL iceConnectionState changes at the right time, with bundle policy max-bundle promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'sender' of undefined"
+FAIL iceConnectionState changes at the right time, with bundle policy max-compat promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'sender' of undefined"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-events-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-events-expected.txt
index 2c113c5..9a5c3c22 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-events-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-events-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Cannot read property 'addEventListener' of null
+Harness Error. harness_status.status = 1 , harness_status.message = Cannot read property 'state' of null
 FAIL SctpTransport objects are created at appropriate times assert_not_equals: got disallowed value null
-FAIL SctpTransport reaches connected and closed state promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'addEventListener' of null"
+FAIL SctpTransport reaches connected and closed state promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'state' of null"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-maxChannels-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-maxChannels-expected.txt
index 41a583a..4d62c3a 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-maxChannels-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-maxChannels-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Cannot read property 'addEventListener' of null
+Harness Error. harness_status.status = 1 , harness_status.message = Cannot read property 'state' of null
 FAIL An unconnected peerconnection must not have maxChannels set assert_not_equals: RTCSctpTransport must be available got disallowed value null
 FAIL maxChannels gets instantiated after connecting promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'maxChannels' of null"
 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/protocol/candidate-exchange.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/protocol/candidate-exchange.https-expected.txt
index affbf0a..c342435 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/protocol/candidate-exchange.https-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/protocol/candidate-exchange.https-expected.txt
@@ -2,5 +2,7 @@
 PASS Two way ICE exchange works
 FAIL Adding only caller -> callee candidates gives a connection promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'transport' of null"
 FAIL Adding only callee -> caller candidates gives a connection promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'transport' of null"
+FAIL Adding callee -> caller candidates from end-of-candidates gives a connection promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'transport' of null"
+FAIL Explicit offer/answer exchange gives a connection promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'transport' of null"
 Harness: the test ran to completion.
 
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 6bed5cd..bd4c486 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-10-0-61-gd1b16325e
-Revision: d1b16325e27b766c27cc9f569c0aa334f1ecb732
+Version: VER-2-10-0-64-ge7ac9288a
+Revision: e7ac9288acde8ad21c96ad9c448ad2b2cfc9fe6a
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
 License File: src/docs/FTL.TXT
diff --git a/tools/android/native_lib_memory/parse_smaps.py b/tools/android/native_lib_memory/parse_smaps.py
index 6cb711c..6113b2a1 100755
--- a/tools/android/native_lib_memory/parse_smaps.py
+++ b/tools/android/native_lib_memory/parse_smaps.py
@@ -101,37 +101,121 @@
   return mappings
 
 
-def ParseProcSmaps(device, pid):
+def ParseProcSmaps(device, pid, store_file=False):
   """Parses /proc/[pid]/smaps on a device, and returns a list of Mapping.
 
   Args:
     device: (device_utils.DeviceUtils) device to parse the file from.
     pid: (int) PID of the process.
+    store_file: (bool) Whether to also write the file to disk.
 
   Returns:
     [Mapping] all the mappings in /proc/[pid]/smaps.
   """
   command = ['cat', '/proc/%d/smaps' % pid]
   lines = device.RunShellCommand(command, check_return=True)
+  if store_file:
+    with open('smaps-%d' % pid, 'w') as f:
+      f.write('\n'.join(lines))
   return _ParseProcSmapsLines(lines)
 
 
-def _PrintSwapStats(mappings):
-  total_swap_kb = sum(m.fields['Swap'] for m in mappings)
-  print 'Total Swap Size (kB) = %d' % total_swap_kb
-  swap_sorted = sorted(mappings, key=lambda m: m.fields['Swap'], reverse=True)
-  for mapping in swap_sorted:
-    swapped = mapping.fields['Swap']
-    if not swapped:
+def _GetPageTableFootprint(device, pid):
+  """Returns the page table footprint for a process in kiB."""
+  command = ['cat', '/proc/%d/status' % pid]
+  lines = device.RunShellCommand(command, check_return=True)
+  for line in lines:
+    if line.startswith('VmPTE:'):
+      value = int(line[len('VmPTE: '):line.index('kB')])
+      return value
+
+
+def _SummarizeMapping(mapping, metric):
+  return '%s %s %s: %d kB (Total Size: %d kB)' % (
+      hex(mapping.start),
+      mapping.pathname, mapping.permissions, metric,
+      (mapping.end - mapping.start) / 1024)
+
+
+def _PrintMappingsMetric(mappings, field_name):
+  """Shows a summary of mappings for a given metric.
+
+  For the given field, compute its aggregate value over all mappings, and
+  prints the mappings sorted by decreasing metric value.
+
+  Args:
+    mappings: ([Mapping]) all process mappings.
+    field_name: (str) Mapping field to process.
+  """
+  total_kb = sum(m.fields[field_name] for m in mappings)
+  print 'Total Size (kB) = %d' % total_kb
+  sorted_by_metric = sorted(mappings,
+                            key=lambda m: m.fields[field_name], reverse=True)
+  for mapping in sorted_by_metric:
+    metric = mapping.fields[field_name]
+    if not metric:
       break
-    print '%s %s: %d kB (Total Size: %d kB)' % (
-        mapping.pathname, mapping.permissions, swapped,
-        (mapping.end - mapping.start) / 1024)
+    print _SummarizeMapping(mapping, metric)
+
+
+def _PrintSwapStats(mappings):
+  print 'SWAP:'
+  _PrintMappingsMetric(mappings, 'Swap')
+
+
+def _PrintEstimatedFootprintStats(mappings, page_table_kb):
+  print 'Private Dirty:'
+  _PrintMappingsMetric(mappings, 'Private_Dirty')
+  print '\n\nShared Dirty:'
+  _PrintMappingsMetric(mappings, 'Shared_Dirty')
+  print '\n\nPrivate Clean:'
+  _PrintMappingsMetric(mappings, 'Private_Clean')
+  print '\n\nShared Clean:'
+  _PrintMappingsMetric(mappings, 'Shared_Clean')
+  print '\n\nSwap PSS:'
+  _PrintMappingsMetric(mappings, 'SwapPss')
+  print '\n\nPage table = %d kiB' % page_table_kb
+
+
+def _ComputeEstimatedFootprint(mappings, page_table_kb):
+  """Returns the estimated footprint in kiB."""
+  footprint = page_table_kb
+  for mapping in mappings:
+    # Chrome shared memory.
+    #
+    # Even though it is shared memory, it exists because the process exists, so
+    # account for its entirety.
+    if mapping.pathname.startswith('/dev/ashmem/shared_memory'):
+      footprint += mapping.fields['Rss']
+    elif mapping.pathname.startswith('[anon:libc_malloc]'):
+      if mapping.fields['Shared_Dirty'] == 0:
+        footprint += mapping.fields['Rss']
+      else:
+        footprint += mapping.fields['Private_Dirty']  # Shared dirty is likely
+                                                      # from the zygote.
+    # Mappings without a name are most likely Chrome's native memory allocators:
+    # v8, PartitionAlloc, Oilpan.
+    # All of it should be charged to our process.
+    elif mapping.pathname.strip() == '':
+      footprint += mapping.fields['Rss']
+    # Often inherited from the zygote, only count the private dirty part,
+    # especially as the swap part likely comes from the zygote.
+    elif mapping.pathname.startswith('['):
+      footprint += mapping.fields['Private_Dirty']
+    # File mappings. Can be a real file, and/or Dalvik/ART.
+    else:
+      footprint += mapping.fields['Private_Dirty']
+  return footprint
 
 
 def _CreateArgumentParser():
   parser = argparse.ArgumentParser()
-  parser.add_argument('--pid', help='PID.', required=True)
+  parser.add_argument('--pid', help='PID.', required=True, type=int)
+  parser.add_argument('--estimate-footprint',
+                      help='Show the estimated memory foootprint',
+                      action='store_true')
+  parser.add_argument('--store-smaps', help='Store the smaps file locally',
+                      action='store_true')
   return parser
 
 
@@ -146,8 +230,14 @@
   device.EnableRoot()
   # Enable logging after device handling as devil is noisy at INFO level.
   logging.basicConfig(level=logging.INFO)
-  mappings = ParseProcSmaps(device, int(args.pid))
-  _PrintSwapStats(mappings)
+  mappings = ParseProcSmaps(device, args.pid, args.store_smaps)
+  if args.estimate_footprint:
+    page_table_kb = _GetPageTableFootprint(device, args.pid)
+    _PrintEstimatedFootprintStats(mappings, page_table_kb)
+    footprint = _ComputeEstimatedFootprint(mappings, page_table_kb)
+    print '\n\nEstimated Footprint = %d kiB' % footprint
+  else:
+    _PrintSwapStats(mappings)
 
 
 if __name__ == '__main__':
diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py
index a133264c..a4bb926 100755
--- a/tools/clang/scripts/package.py
+++ b/tools/clang/scripts/package.py
@@ -15,7 +15,7 @@
 import sys
 import tarfile
 
-from update import RELEASE_VERSION
+from update import RELEASE_VERSION, STAMP_FILE
 
 # Path constants.
 THIS_DIR = os.path.dirname(__file__)
@@ -30,7 +30,6 @@
 LLVM_RELEASE_DIR = os.path.join(LLVM_BUILD_DIR, 'Release+Asserts')
 EU_STRIP = os.path.join(BUILDTOOLS_DIR, 'third_party', 'eu-strip', 'bin',
                         'eu-strip')
-STAMP_FILE = os.path.join(LLVM_BUILD_DIR, 'cr_build_revision')
 
 
 def Tee(output, logfile):
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 58c67bff..e24cc3b 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -25047,6 +25047,14 @@
   <int value="4" label="optional"/>
 </enum>
 
+<enum name="FontScanningResult">
+  <int value="0" label="Success"/>
+  <int value="1" label="FT_New_Face from file failed"/>
+  <int value="2" label="Zero name table entries"/>
+  <int value="3" label="Unable to retrieve name table entry"/>
+  <int value="4" label="Name string is invalid unicode"/>
+</enum>
+
 <enum name="FormDataDeserializationStatus">
   <int value="0" label="Login database success"/>
   <int value="1" label="Login database failure"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 30d5d9d..bb82fc1 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -12610,6 +12610,62 @@
   </summary>
 </histogram>
 
+<histogram name="Blink.Fonts.AndroidFontScanningLoadFromFileSuccess"
+    enum="BooleanSuccess" expires_after="M82">
+  <owner>drott@chromium.org</owner>
+  <owner>layout-dev@chromium.org</owner>
+  <summary>
+    Counts the ratio of whether it was possible to load the font table from file
+    successfully or not. Reported when the font unique name lookup table is
+    loaded at browser startup on Android.
+  </summary>
+</histogram>
+
+<histogram name="Blink.Fonts.AndroidFontScanningPersistToFileSuccess"
+    enum="BooleanSuccess" expires_after="M82">
+  <owner>drott@chromium.org</owner>
+  <owner>layout-dev@chromium.org</owner>
+  <summary>
+    Counts the ratio of whether it was possible to store the font table to disk
+    after the metadata has been indexed. Reported on Android when the font
+    unique name lookup table is stored after indexing.
+  </summary>
+</histogram>
+
+<histogram name="Blink.Fonts.AndroidFontScanningResult"
+    enum="FontScanningResult" expires_after="M82">
+  <owner>drott@chromium.org</owner>
+  <owner>layout-dev@chromium.org</owner>
+  <summary>
+    Reports success or failure of extracting metadata from a single font file.
+    Reported when the font unique name lookup table is rebuilt on Android (i.e.
+    after a firmware update or first start with empty cache folder).
+  </summary>
+</histogram>
+
+<histogram name="Blink.Fonts.AndroidFontScanningTableBuildTime" units="ms"
+    expires_after="M82">
+  <owner>drott@chromium.org</owner>
+  <owner>layout-dev@chromium.org</owner>
+  <summary>
+    Records duration of scanning available fonts for font name metadata, sorting
+    the list and making it available to renderers. Reported when the font unique
+    name lookup table is rebuilt on Android (i.e. after a firmware update or
+    first start with empty cache folder).
+  </summary>
+</histogram>
+
+<histogram name="Blink.Fonts.AndroidFontScanningUpdateNeeded"
+    enum="BooleanSuccess" expires_after="M82">
+  <owner>drott@chromium.org</owner>
+  <owner>layout-dev@chromium.org</owner>
+  <summary>
+    Counts the ratio of whether it was necessary to rebuild the font table or
+    not. Reported when after the unique name lookup table is loaded from disk at
+    browser startup on Android.
+  </summary>
+</histogram>
+
 <histogram name="Blink.Fonts.HarfBuzzFaceZeroCopyAccess" enum="BooleanSuccess"
     expires_after="M82">
   <owner>drott@chromium.org</owner>
@@ -50626,6 +50682,17 @@
   </summary>
 </histogram>
 
+<histogram name="IOS.WKWebViewStartProvisionalNavigationWithEmptyURL"
+    enum="Boolean" expires_after="M78">
+  <owner>mrsuyi@chromium.org</owner>
+  <owner>eugenebut@chromium.org</owner>
+  <summary>
+    On iOS9, didStartProvisionalNavigation may be called with empty URL. However
+    in didCommitNavigation the URL will be about:blank. This historgram checks
+    if this still happens in later iOS versions, and records it when it happens.
+  </summary>
+</histogram>
+
 <histogram name="IPC.AttachmentBrokerPrivileged.BrokerAttachmentError"
     enum="IPCAttachmentBrokerPrivilegedBrokerAttachmentError">
   <owner>erikchen@chromium.org</owner>
diff --git a/ui/android/java/res/color/chip_text_color_secondary.xml b/ui/android/java/res/color/chip_text_color_secondary.xml
new file mode 100644
index 0000000..956797f8
--- /dev/null
+++ b/ui/android/java/res/color/chip_text_color_secondary.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@color/chip_text_color_selected" android:state_selected="true" />
+    <item android:color="@color/chip_text_color_secondary_default" />
+</selector>
diff --git a/ui/android/java/res/values-v17/styles.xml b/ui/android/java/res/values-v17/styles.xml
index 11c4ec2d..aaf6cba1 100644
--- a/ui/android/java/res/values-v17/styles.xml
+++ b/ui/android/java/res/values-v17/styles.xml
@@ -64,15 +64,16 @@
         <item name="android:gravity">center_vertical</item>
         <item name="android:orientation">horizontal</item>
         <item name="chipColor">@color/chip_background_color</item>
+        <item name="primaryTextAppearance">@style/TextAppearance.ChipText</item>
+        <item name="secondaryTextAppearance">@style/TextAppearance.ChipHint</item>
         <item name="rippleColor">@color/chip_ripple_color</item>
         <item name="verticalInset">@dimen/chip_bg_vertical_inset</item>
     </style>
     <style name="SuggestionChip" parent="Chip" tools:ignore="UnusedResources">
-        <item name="primaryTextAppearance">@style/TextAppearance.ChipText</item>
+        <item name="primaryTextAppearance">@style/TextAppearance.ChipHint</item>
         <item name="cornerRadius">@dimen/chip_corner_radius</item>
     </style>
     <style name="InputChip" parent="Chip" tools:ignore="UnusedResources">
-        <item name="primaryTextAppearance">@style/TextAppearance.ChipText</item>
         <item name="cornerRadius">@dimen/chip_default_height</item>
     </style>
     <style name="AssistiveChip" parent="Chip" tools:ignore="UnusedResources">
@@ -235,6 +236,10 @@
         <item name="android:textColor">@color/chip_text_color</item>
         <item name="android:textSize">@dimen/text_size_medium</item>
     </style>
+    <style name="TextAppearance.ChipHint" parent="TextAppearance.AccentMediumStyle">
+        <item name="android:textColor">@color/chip_text_color_secondary</item>
+        <item name="android:textSize">@dimen/text_size_medium</item>
+    </style>
 
     <!-- Dividers -->
     <style name="HorizontalDivider"
diff --git a/ui/android/java/res/values/colors.xml b/ui/android/java/res/values/colors.xml
index 33fa893f..85c6bf746 100644
--- a/ui/android/java/res/values/colors.xml
+++ b/ui/android/java/res/values/colors.xml
@@ -70,8 +70,9 @@
     <color name="ripple_color_blue">@color/modern_blue_600</color>
 
     <!-- Chip colors -->
-    <color name="chip_text_color_default">@color/default_text_color_secondary</color>
+    <color name="chip_text_color_default">@color/default_text_color</color>
     <color name="chip_text_color_selected">@color/default_text_color_link</color>
+    <color name="chip_text_color_secondary_default">@color/default_text_color_secondary</color>
     <color name="chip_background_color_disabled">@color/modern_grey_100_alpha_38</color>
     <color name="chip_ripple_color_default">@color/modern_grey_800</color>
 
diff --git a/ui/android/java/res_night/values-night/colors.xml b/ui/android/java/res_night/values-night/colors.xml
index 74a8cbd6..1979ef9f 100644
--- a/ui/android/java/res_night/values-night/colors.xml
+++ b/ui/android/java/res_night/values-night/colors.xml
@@ -35,7 +35,6 @@
     <color name="ripple_color_blue">@color/modern_blue_300</color>
 
     <!-- Chip colors -->
-    <color name="chip_text_color_default">@color/default_text_color_light</color>
     <color name="chip_text_color_selected">@color/default_text_color_dark</color>
     <color name="chip_background_color_disabled">@color/modern_grey_300_alpha_38</color>
     <color name="chip_ripple_color_default">@android:color/white</color>
diff --git a/ui/chromeos/file_manager_strings.grdp b/ui/chromeos/file_manager_strings.grdp
index ca673b2c..a32f0f1 100644
--- a/ui/chromeos/file_manager_strings.grdp
+++ b/ui/chromeos/file_manager_strings.grdp
@@ -603,6 +603,9 @@
   <message name="IDS_FILE_BROWSER_CANCEL_SELECTION_BUTTON_LABEL" desc="Label for button that unselects all selected items.">
     Cancel selection
   </message>
+  <message name="IDS_FILE_BROWSER_READ_ONLY_LABEL" desc="Label for an indicator which means that the current folder is read-only.">
+    Read only
+  </message>
   <message name="IDS_FILE_BROWSER_CHANGE_TO_LISTVIEW_BUTTON_LABEL" desc="Label for button that changes the view mode to 'list view' mode.">
     Switch to list view
   </message>
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_READ_ONLY_LABEL.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_READ_ONLY_LABEL.png.sha1
new file mode 100644
index 0000000..a010d24
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_READ_ONLY_LABEL.png.sha1
@@ -0,0 +1 @@
+3f24b79e981374576ae28191874fea6b7e43d896
\ No newline at end of file
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index dd9fc92c..fa80b5d 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -879,7 +879,6 @@
 .breadcrumbs {
   align-items: center;
   display: flex;
-  flex: auto;
   flex-direction: row;
   overflow: hidden;
 }
@@ -961,6 +960,36 @@
   transform: scaleX(-1);
 }
 
+/* The toolbar indicator that means the current directory is read only. */
+#read-only-indicator {
+  align-items: center;
+  background-color: rgba(0, 0, 0, 0.2);
+  border-radius: 16px;
+  display: flex;
+  flex: none;
+  height: 32px;
+  margin-inline-start: 4px;
+  padding: 0 16px;
+}
+
+body.check-select #read-only-indicator {
+  display: none;
+}
+
+#read-only-icon {
+  background-image: url(../images/files/ui/visibility_white.svg);
+  flex: none;
+  height: 16px;
+  margin-inline-end: 8px;
+  width: 16px;
+}
+
+#read-only-label {
+  flex: none;
+  font-size: 13px;
+  font-weight: 500;
+}
+
 .filelist-panel {
   display: flex;
   flex: auto;
diff --git a/ui/file_manager/file_manager/foreground/images/files/ui/visibility_white.svg b/ui/file_manager/file_manager/foreground/images/files/ui/visibility_white.svg
new file mode 100644
index 0000000..3e883af
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/files/ui/visibility_white.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="0 0 48 48" fill="#FFFFFF">
+    <path d="M0 0h48v48H0z" fill="none"/>
+    <path d="M24 9C14 9 5.46 15.22 2 24c3.46 8.78 12 15 22 15 10.01 0 18.54-6.22 22-15-3.46-8.78-11.99-15-22-15zm0 25c-5.52 0-10-4.48-10-10s4.48-10 10-10 10 4.48 10 10-4.48 10-10 10zm0-16c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6z"/>
+</svg>
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index 2e793ca..63b23a66 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -51,23 +51,41 @@
  * @return {!Array<!Entry>} Entries of the found node.
  */
 CommandUtil.getCommandEntries = (fileManager, element) => {
+  // DirectoryItem has "entry" attribute.
   if (element && element.entry) {
-    // DirectoryItem has "entry" attribute.
     return [element.entry];
-  } else if (element.selectedItem && element.selectedItem.entry) {
-    // DirectoryTree has the selected item.
+  }
+
+  // DirectoryTree has the selected item.
+  if (element.selectedItem && element.selectedItem.entry) {
     return [element.selectedItem.entry];
-  } else if (element.selectedItems && element.selectedItems.length) {
-    // File list (cr.ui.List).
+  }
+
+  // File list (cr.ui.List).
+  if (element.selectedItems && element.selectedItems.length) {
     const entries = element.selectedItems;
     // Check if it is Entry or not by checking for toURL().
     return entries.filter(entry => ('toURL' in entry));
-  } else if (fileManager.ui.actionbar.contains(/** @type {Node} */ (element))) {
-    // Commands in the action bar can only act in the currently selected files.
-    return fileManager.getSelection().entries;
-  } else {
-    return [];
   }
+
+  // Commands in the action bar can only act in the currently selected files.
+  if (fileManager.ui.actionbar.contains(/** @type {Node} */ (element))) {
+    return fileManager.getSelection().entries;
+  }
+
+  // Context Menu: redirect to the element the context menu is displayed for.
+  if (element.contextElement) {
+    return CommandUtil.getCommandEntries(fileManager, element.contextElement);
+  }
+
+  // Context Menu Item: redirect to the element the context menu is displayed
+  // for.
+  if (element.parentElement.contextElement) {
+    return CommandUtil.getCommandEntries(
+        fileManager, element.parentElement.contextElement);
+  }
+
+  return [];
 };
 
 /**
@@ -346,6 +364,9 @@
      */
     this.commands_ = {};
 
+    /** @private {?Element} */
+    this.lastFocusedElement_ = null;
+
     // Decorate command tags in the document.
     const commands = fileManager.document.querySelectorAll('command');
     for (let i = 0; i < commands.length; i++) {
@@ -359,10 +380,10 @@
     fileManager.document.addEventListener(
         'canExecute', this.onCanExecute_.bind(this));
 
-    // TODO(lucmult): Try to remove this event listener to avoid flickering.
-    selectionHandler.addEventListener(
-        FileSelectionHandler.EventType.CHANGE_THROTTLED,
-        this.updateAvailability.bind(this));
+    cr.ui.contextMenuHandler.addEventListener(
+        'show', this.onContextMenuShow_.bind(this));
+    cr.ui.contextMenuHandler.addEventListener(
+        'hide', this.onContextMenuHide_.bind(this));
 
     chrome.commandLinePrivate.hasSwitch(
         'disable-zip-archiver-packer', disabled => {
@@ -370,12 +391,20 @@
         });
   }
 
-  /**
-   * Updates the availability of all commands.
-   */
-  updateAvailability() {
-    for (const id in this.commands_) {
-      this.commands_[id].canExecuteChange();
+  /** @param {!Event} event */
+  onContextMenuShow_(event) {
+    this.lastFocusedElement_ = document.activeElement;
+    const menu = event.menu;
+    // Set focus asynchronously to give time for menu "show" event to finish and
+    // have all items set up before focusing.
+    setTimeout(() => menu.focusSelectedItem(), 0);
+  }
+
+  /** @param {!Event} event */
+  onContextMenuHide_(event) {
+    if (this.lastFocusedElement_) {
+      this.lastFocusedElement_.focus();
+      this.lastFocusedElement_ = null;
     }
   }
 
@@ -1481,7 +1510,6 @@
         });
   }
 
-
   /** @override */
   canExecute(event, fileManager) {
     const entries = CommandUtil.getCommandEntries(fileManager, event.target);
@@ -1591,6 +1619,7 @@
 CommandHandler.COMMANDS_['share'] = new class extends Command {
   execute(event, fileManager) {
     const entries = CommandUtil.getCommandEntries(fileManager, event.target);
+    const actionsController = fileManager.actionsController;
 
     fileManager.actionsController.getActionsForEntries(entries).then(
         (/** ?ActionsModel */ actionsModel) => {
@@ -1600,7 +1629,7 @@
           const action =
               actionsModel.getAction(ActionsModel.CommonActionId.SHARE);
           if (action) {
-            action.execute();
+            actionsController.executeAction(action);
           }
         });
   }
@@ -1650,6 +1679,7 @@
 CommandHandler.COMMANDS_['manage-in-drive'] = new class extends Command {
   execute(event, fileManager) {
     const entries = CommandUtil.getCommandEntries(fileManager, event.target);
+    const actionsController = fileManager.actionsController;
 
     fileManager.actionsController.getActionsForEntries(entries).then(
         (/** ?ActionsModel */ actionsModel) => {
@@ -1659,7 +1689,7 @@
           const action = actionsModel.getAction(
               ActionsModel.InternalActionId.MANAGE_IN_DRIVE);
           if (action) {
-            action.execute();
+            actionsController.executeAction(action);
           }
         });
   }
@@ -1945,6 +1975,8 @@
 CommandHandler.COMMANDS_['create-folder-shortcut'] = new class extends Command {
   execute(event, fileManager) {
     const entries = CommandUtil.getCommandEntries(fileManager, event.target);
+    const actionsController = fileManager.actionsController;
+
     fileManager.actionsController.getActionsForEntries(entries).then(
         (/** ?ActionsModel */ actionsModel) => {
           if (!actionsModel) {
@@ -1953,7 +1985,7 @@
           const action = actionsModel.getAction(
               ActionsModel.InternalActionId.CREATE_FOLDER_SHORTCUT);
           if (action) {
-            action.execute();
+            actionsController.executeAction(action);
           }
         });
   }
@@ -2005,6 +2037,7 @@
 CommandHandler.COMMANDS_['remove-folder-shortcut'] = new class extends Command {
   execute(event, fileManager) {
     const entries = CommandUtil.getCommandEntries(fileManager, event.target);
+    const actionsController = fileManager.actionsController;
 
     fileManager.actionsController.getActionsForEntries(entries).then(
         (/** ?ActionsModel */ actionsModel) => {
@@ -2014,7 +2047,7 @@
           const action = actionsModel.getAction(
               ActionsModel.InternalActionId.REMOVE_FOLDER_SHORTCUT);
           if (action) {
-            action.execute();
+            actionsController.executeAction(action);
           }
         });
   }
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.js b/ui/file_manager/file_manager/foreground/js/file_tasks.js
index fe6c5b3..0827a9c5 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -984,6 +984,10 @@
     let moreActionsSeparator =
         shareMenuButton.menu.querySelector('#more-actions-separator');
 
+    // Update share command.
+    driveShareCommand.command.canExecuteChange(
+        this.ui_.listContainer.currentList);
+
     // Hide share icon for New Folder creation.  See https://crbug.com/571355.
     shareMenuButton.hidden =
         (driveShareCommand.disabled && tasks.length == 0) ||
diff --git a/ui/file_manager/file_manager/foreground/js/toolbar_controller.js b/ui/file_manager/file_manager/foreground/js/toolbar_controller.js
index 2fc32aa..980a146 100644
--- a/ui/file_manager/file_manager/foreground/js/toolbar_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/toolbar_controller.js
@@ -57,6 +57,13 @@
     this.deleteButton_ = queryRequiredElement('#delete-button', this.toolbar_);
 
     /**
+     * @private {!HTMLElement}
+     * @const
+     */
+    this.readOnlyIndicator_ =
+        queryRequiredElement('#read-only-indicator', this.toolbar_);
+
+    /**
      * @private {!cr.ui.Command}
      * @const
      */
@@ -143,7 +150,7 @@
   }
 
   /**
-   * Updates buttons that act on current directory.
+   * Updates toolbar's UI elements which are related to current directory.
    * @private
    */
   updateCurrentDirectoryButtons_() {
@@ -152,6 +159,11 @@
     this.refreshCommand_.setHidden(
         volumeInfo && volumeInfo.watchable ||
         this.directoryModel_.getFileListSelection().getCheckSelectMode());
+
+    const currentDirectory = this.directoryModel_.getCurrentDirEntry();
+    const locationInfo = currentDirectory &&
+        this.volumeManager_.getLocationInfo(currentDirectory);
+    this.readOnlyIndicator_.hidden = !(locationInfo && locationInfo.isReadOnly);
   }
 
   /**
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler.js b/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler.js
index 269cb38..a5bc1376 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler.js
@@ -8,8 +8,6 @@
  * the user of this class can choose to either handle the event as a tap
  * distincted from mouse clicks, or leave it handled by the mouse event
  * handlers by default.
- *
- * @constructor
  */
 class FileTapHandler {
   constructor() {
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index 93bc1bee..a96ee05 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -359,6 +359,10 @@
 
     <div class="dialog-header" role="contentinfo">
       <div id="location-breadcrumbs" class="breadcrumbs"></div>
+      <div id="read-only-indicator" hidden>
+        <span id="read-only-icon"></span>
+        <span id="read-only-label">$i18n{READ_ONLY_LABEL}</span>
+      </div>
       <div id="cancel-selection-button-wrapper">
         <cr-button id="cancel-selection-button" class="menu-button" tabindex="8"
               aria-label="$i18n{CANCEL_SELECTION_BUTTON_LABEL}" has-tooltip>
diff --git a/ui/file_manager/integration_tests/file_manager/context_menu.js b/ui/file_manager/integration_tests/file_manager/context_menu.js
index 30569fb8..09ae5d21 100644
--- a/ui/file_manager/integration_tests/file_manager/context_menu.js
+++ b/ui/file_manager/integration_tests/file_manager/context_menu.js
@@ -609,3 +609,31 @@
   return checkDocumentsProviderContextMenu(
       'rename', 'Renamable File.txt', true);
 };
+
+/**
+ * Tests that context menu in file list gets the focus, so ChromeVox can
+ * announce it.
+ */
+testcase.checkContextMenuFocus = async () => {
+  // Open Files App on Downloads.
+  const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
+
+  // Select the file |path|.
+  chrome.test.assertTrue(!!await remoteCall.callRemoteTestUtil(
+      'selectFile', appId, ['hello.txt']));
+
+  // Wait for the file to be selected.
+  await remoteCall.waitForElement(appId, '.table-row[selected]');
+
+  // Right-click the selected file.
+  chrome.test.assertTrue(!!await remoteCall.callRemoteTestUtil(
+      'fakeMouseRightClick', appId, ['.table-row[selected]']));
+
+  // Wait for the context menu to appear.
+  await remoteCall.waitForElement(appId, '#file-context-menu:not([hidden])');
+
+  // Check currently focused element.
+  const focusedElement =
+      await remoteCall.callRemoteTestUtil('getActiveElement', appId, []);
+  chrome.test.assertEq('menuitem', focusedElement.attributes.role);
+};
diff --git a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
index bbfd4c9..6900e3de 100644
--- a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
+++ b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
@@ -1412,4 +1412,32 @@
     await checkContextMenu(
         appId, '/Computers/Computer A/A', folderMenus, false /* rootMenu */);
   };
+
+  /**
+   * Tests that context menu in directory tree gets the focus, so ChromeVox can
+   * announce it.
+   */
+  testcase.dirContextMenuFocus = async () => {
+    // Open Files app on local Downloads.
+    const appId =
+        await setupAndWaitUntilReady(RootPath.DOWNLOADS, [ENTRIES.photos], []);
+
+    // Right-click /My files/Downloads in the directory tree.
+    const query =
+        '#directory-tree [entry-label="My files"] [entry-label="Downloads"]';
+    await remoteCall.waitForElement(appId, query);
+
+    // Right-click the selected file.
+    chrome.test.assertTrue(!!await remoteCall.callRemoteTestUtil(
+        'fakeMouseRightClick', appId, [query]));
+
+    // Wait for the context menu to appear.
+    await remoteCall.waitForElement(
+        appId, '#directory-tree-context-menu:not([hidden])');
+
+    // Check currently focused element.
+    const focusedElement =
+        await remoteCall.callRemoteTestUtil('getActiveElement', appId, []);
+    chrome.test.assertEq('menuitem', focusedElement.attributes.role);
+  };
 })();
diff --git a/ui/file_manager/integration_tests/file_manager/file_display.js b/ui/file_manager/integration_tests/file_manager/file_display.js
index 114f90d9..428f8ea 100644
--- a/ui/file_manager/integration_tests/file_manager/file_display.js
+++ b/ui/file_manager/integration_tests/file_manager/file_display.js
@@ -856,3 +856,37 @@
   // Make sure check-select is enabled.
   await remoteCall.waitForElement(appId, 'body.check-select');
 };
+
+/**
+ * Tests to make sure read-only indicator is visible when the current directory
+ * is read-only.
+ */
+testcase.fileDisplayCheckReadOnlyIconOnFakeDirectory = async () => {
+  // Open Files app on Drive with the given test files.
+  const appId = await setupAndWaitUntilReady(
+      RootPath.DRIVE, [ENTRIES.newlyAdded],
+      [ENTRIES.testSharedDocument, ENTRIES.hello]);
+
+  // Navigate to Shared with me.
+  await remoteCall.callRemoteTestUtil(
+      'fakeMouseClick', appId, ['[volume-type-icon=\'drive_shared_with_me\']']);
+
+  // Wait for the navigation to complete.
+  await remoteCall.waitUntilCurrentDirectoryIsChanged(appId, '/Shared with me');
+
+  // Make sure read-only indicator on toolbar is visible.
+  await remoteCall.waitForElement(appId, '#read-only-indicator:not([hidden])');
+};
+
+/**
+ * Tests to make sure read-only indicator is NOT visible when the current
+ * is writable.
+ */
+testcase.fileDisplayCheckNoReadOnlyIconOnDownloads = async () => {
+  // Open files app on Downloads containing ENTRIES.hello.
+  const appId =
+      await setupAndWaitUntilReady(RootPath.DOWNLOADS, [ENTRIES.hello], []);
+
+  // Make sure read-only indicator on toolbar is NOT visible.
+  await remoteCall.waitForElement(appId, '#read-only-indicator[hidden]');
+};
diff --git a/ui/latency/ipc/OWNERS b/ui/latency/ipc/OWNERS
index d006840d..38a3112a 100644
--- a/ui/latency/ipc/OWNERS
+++ b/ui/latency/ipc/OWNERS
@@ -1,15 +1,9 @@
 set noparent
-dcheng@chromium.org
-inferno@chromium.org
-jln@chromium.org
-jschuh@chromium.org
-kenrb@chromium.org
-nasko@chromium.org
-palmer@chromium.org
-tsepez@chromium.org
+file://ipc/SECURITY_OWNERS
 
 per-file BUILD.gn=*
 
+# The following lines are redundant, they're just to silence the presubmit
 per-file *_param_traits*.*=set noparent
 per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS
 
diff --git a/ui/ozone/platform/scenic/BUILD.gn b/ui/ozone/platform/scenic/BUILD.gn
index 59d1d8ae..67d670f 100644
--- a/ui/ozone/platform/scenic/BUILD.gn
+++ b/ui/ozone/platform/scenic/BUILD.gn
@@ -63,16 +63,11 @@
     "//ui/platform_window",
   ]
 
-  data_deps = []
   if (enable_vulkan) {
     sources += [
       "vulkan_implementation_scenic.cc",
       "vulkan_implementation_scenic.h",
     ]
     defines += [ "VK_USE_PLATFORM_MAGMA_KHR" ]
-    data_deps += [
-      "//third_party/angle:libEGL",
-      "//third_party/angle:libGLESv2",
-    ]
   }
 }
diff --git a/ui/ozone/platform/scenic/scenic_surface_factory.cc b/ui/ozone/platform/scenic/scenic_surface_factory.cc
index dca85fa..6e892e3 100644
--- a/ui/ozone/platform/scenic/scenic_surface_factory.cc
+++ b/ui/ozone/platform/scenic/scenic_surface_factory.cc
@@ -84,16 +84,14 @@
 
 std::vector<gl::GLImplementation>
 ScenicSurfaceFactory::GetAllowedGLImplementations() {
-  return std::vector<gl::GLImplementation>{
-      gl::kGLImplementationSwiftShaderGL,
-      gl::kGLImplementationEGLGLES2,
-  };
+  // TODO(spang): Remove this after crbug.com/897208 is fixed.
+  return std::vector<gl::GLImplementation>{gl::kGLImplementationSwiftShaderGL,
+                                           gl::kGLImplementationStubGL};
 }
 
 GLOzone* ScenicSurfaceFactory::GetGLOzone(gl::GLImplementation implementation) {
   switch (implementation) {
     case gl::kGLImplementationSwiftShaderGL:
-    case gl::kGLImplementationEGLGLES2:
       return egl_implementation_.get();
     default:
       return nullptr;
diff --git a/ui/ozone/platform/wayland/host/wayland_clipboard.h b/ui/ozone/platform/wayland/host/wayland_clipboard.h
index 61daf6a..8fcbfae 100644
--- a/ui/ozone/platform/wayland/host/wayland_clipboard.h
+++ b/ui/ozone/platform/wayland/host/wayland_clipboard.h
@@ -22,7 +22,7 @@
  public:
   WaylandClipboard(WaylandDataDeviceManager* data_device_manager,
                    WaylandDataDevice* data_device);
-  virtual ~WaylandClipboard();
+  ~WaylandClipboard() override;
 
   // PlatformClipboard.
   void OfferClipboardData(
diff --git a/ui/ozone/platform/x11/BUILD.gn b/ui/ozone/platform/x11/BUILD.gn
index 0735b4f..b181984 100644
--- a/ui/ozone/platform/x11/BUILD.gn
+++ b/ui/ozone/platform/x11/BUILD.gn
@@ -20,6 +20,8 @@
     "gl_surface_glx_ozone.h",
     "ozone_platform_x11.cc",
     "ozone_platform_x11.h",
+    "x11_clipboard.cc",
+    "x11_clipboard.h",
     "x11_cursor_factory_ozone.cc",
     "x11_cursor_factory_ozone.h",
     "x11_cursor_ozone.cc",
diff --git a/ui/ozone/platform/x11/ozone_platform_x11.cc b/ui/ozone/platform/x11/ozone_platform_x11.cc
index af42f42..ec40bcc 100644
--- a/ui/ozone/platform/x11/ozone_platform_x11.cc
+++ b/ui/ozone/platform/x11/ozone_platform_x11.cc
@@ -16,6 +16,7 @@
 #include "ui/events/system_input_injector.h"
 #include "ui/gfx/x/x11.h"
 #include "ui/ozone/common/stub_overlay_manager.h"
+#include "ui/ozone/platform/x11/x11_clipboard.h"
 #include "ui/ozone/platform/x11/x11_cursor_factory_ozone.h"
 #include "ui/ozone/platform/x11/x11_screen_ozone.h"
 #include "ui/ozone/platform/x11/x11_surface_factory.h"
@@ -81,12 +82,17 @@
     return std::make_unique<X11ScreenOzone>();
   }
 
+  PlatformClipboard* GetPlatformClipboard() override {
+    return clipboard_.get();
+  }
+
   void InitializeUI(const InitParams& params) override {
     InitializeCommon(params);
     CreatePlatformEventSource();
     window_manager_ = std::make_unique<X11WindowManagerOzone>();
     overlay_manager_ = std::make_unique<StubOverlayManager>();
     input_controller_ = CreateStubInputController();
+    clipboard_ = std::make_unique<X11Clipboard>();
     cursor_factory_ozone_ = std::make_unique<X11CursorFactoryOzone>();
     gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
 
@@ -145,6 +151,7 @@
   std::unique_ptr<X11WindowManagerOzone> window_manager_;
   std::unique_ptr<OverlayManagerOzone> overlay_manager_;
   std::unique_ptr<InputController> input_controller_;
+  std::unique_ptr<X11Clipboard> clipboard_;
   std::unique_ptr<X11CursorFactoryOzone> cursor_factory_ozone_;
   std::unique_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
 
diff --git a/ui/ozone/platform/x11/x11_clipboard.cc b/ui/ozone/platform/x11/x11_clipboard.cc
new file mode 100644
index 0000000..b512b16
--- /dev/null
+++ b/ui/ozone/platform/x11/x11_clipboard.cc
@@ -0,0 +1,56 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <utility>
+
+#include "ui/ozone/platform/x11/x11_clipboard.h"
+
+namespace ui {
+
+X11Clipboard::X11Clipboard() = default;
+X11Clipboard::~X11Clipboard() = default;
+
+void X11Clipboard::OfferClipboardData(
+    const PlatformClipboard::DataMap& data_map,
+    PlatformClipboard::OfferDataClosure callback) {
+  // TODO(crbug.com/973295): Implement X11Clipboard
+  NOTIMPLEMENTED_LOG_ONCE();
+  std::move(callback).Run();
+}
+
+void X11Clipboard::RequestClipboardData(
+    const std::string& mime_type,
+    PlatformClipboard::DataMap* data_map,
+    PlatformClipboard::RequestDataClosure callback) {
+  // TODO(crbug.com/973295): Implement X11Clipboard
+  NOTIMPLEMENTED_LOG_ONCE();
+  std::move(callback).Run({});
+}
+
+void X11Clipboard::GetAvailableMimeTypes(
+    PlatformClipboard::GetMimeTypesClosure callback) {
+  // TODO(crbug.com/973295): Implement X11Clipboard
+  NOTIMPLEMENTED_LOG_ONCE();
+  std::move(callback).Run({});
+}
+
+bool X11Clipboard::IsSelectionOwner() {
+  // TODO(crbug.com/973295): Implement X11Clipboard
+  NOTIMPLEMENTED_LOG_ONCE();
+  return false;
+}
+
+void X11Clipboard::SetSequenceNumberUpdateCb(
+    PlatformClipboard::SequenceNumberUpdateCb cb) {
+  DCHECK(update_sequence_cb_.is_null())
+      << " The callback can be installed only once.";
+  update_sequence_cb_ = std::move(cb);
+}
+
+void X11Clipboard::UpdateSequenceNumber() {
+  if (!update_sequence_cb_.is_null())
+    update_sequence_cb_.Run();
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/x11/x11_clipboard.h b/ui/ozone/platform/x11/x11_clipboard.h
new file mode 100644
index 0000000..120210cd6
--- /dev/null
+++ b/ui/ozone/platform/x11/x11_clipboard.h
@@ -0,0 +1,46 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_X11_X11_CLIPBOARD_H_
+#define UI_OZONE_PLATFORM_X11_X11_CLIPBOARD_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "ui/ozone/public/platform_clipboard.h"
+
+namespace ui {
+
+// Handles clipboard operations for X11 Platform
+class X11Clipboard : public PlatformClipboard {
+ public:
+  X11Clipboard();
+  ~X11Clipboard() override;
+
+  // PlatformClipboard.
+  void OfferClipboardData(
+      const PlatformClipboard::DataMap& data_map,
+      PlatformClipboard::OfferDataClosure callback) override;
+  void RequestClipboardData(
+      const std::string& mime_type,
+      PlatformClipboard::DataMap* data_map,
+      PlatformClipboard::RequestDataClosure callback) override;
+  void GetAvailableMimeTypes(
+      PlatformClipboard::GetMimeTypesClosure callback) override;
+  bool IsSelectionOwner() override;
+  void SetSequenceNumberUpdateCb(
+      PlatformClipboard::SequenceNumberUpdateCb cb) override;
+
+ private:
+  void UpdateSequenceNumber();
+
+  // Notifies whenever clipboard sequence number is changed.
+  PlatformClipboard::SequenceNumberUpdateCb update_sequence_cb_;
+
+  DISALLOW_COPY_AND_ASSIGN(X11Clipboard);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_X11_X11_CLIPBOARD_H_
diff --git a/ui/ozone/public/platform_clipboard.h b/ui/ozone/public/platform_clipboard.h
index 4963e24d..99c9502 100644
--- a/ui/ozone/public/platform_clipboard.h
+++ b/ui/ozone/public/platform_clipboard.h
@@ -21,6 +21,8 @@
 //
 class OZONE_BASE_EXPORT PlatformClipboard {
  public:
+  virtual ~PlatformClipboard() {}
+
   // DataMap is a map from "mime type" to associated data, whereas
   // the data can be organized differently for each mime type.
   using Data = std::vector<uint8_t>;
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.html b/ui/webui/resources/cr_components/chromeos/network/network_config.html
index 6461170..654a6f4f 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_config.html
+++ b/ui/webui/resources/cr_components/chromeos/network/network_config.html
@@ -1,11 +1,7 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
 <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
-<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
-<link rel="import" href="chrome://resources/html/action_link.html">
-<link rel="import" href="chrome://resources/html/action_link_css.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
@@ -18,7 +14,7 @@
 
 <dom-module id="network-config">
   <template>
-    <style include="network-shared settings-shared action-link iron-flex">
+    <style include="network-shared iron-flex">
       #spinner-container {
         height: 200px;
       }
@@ -189,31 +185,6 @@
           </cr-toggle>
         </div>
       </template>
-
-      <!-- AutoConnect (WiFi) -->
-      <template is="dom-if" if="[[configCanAutoConnect_(type)]]" restamp>
-        <div class="property-box">
-          <div id="autoConnectLabel"
-              class="start">[[i18n('networkAutoConnect')]]</div>
-          <template is="dom-if"
-              if="[[isAutoConnectEnforcedByPolicy_(globalPolicy)]]" restamp>
-            <cr-policy-indicator indicator-type="devicePolicy">
-            </cr-policy-indicator>
-          </template>
-          <cr-toggle id="autoConnect" checked="{{autoConnect_}}"
-              disabled="[[autoConnectDisabled_(globalPolicy)]]"
-              aria-labeledby="autoConnectLabel">
-          </cr-toggle>
-        </div>
-      </template>
-
-      <!-- Hidden Network Warning -->
-      <template is="dom-if" if="{{autoConnect_}}" restamp>
-        <div>
-          <iron-icon icon="cr:warning"></iron-icon>
-          [[i18nAdvanced('hiddenNetworkWarning')]]
-        </div>
-      </template>
     </template>
   </template>
   <script src="network_config.js"></script>
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.js b/ui/webui/resources/cr_components/chromeos/network/network_config.js
index 83396a86..2b7bb47a 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_config.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_config.js
@@ -181,12 +181,6 @@
     },
 
     /**
-     * Whether the device should automatically connect to the network.
-     * @private
-     */
-    autoConnect_: Boolean,
-
-    /**
      * Security value, used for Ethernet and Wifi and to detect when Security
      * changes.
      * @private
@@ -391,15 +385,6 @@
     } else {
       this.focusFirstInput_();
     }
-
-    if (this.type == CrOnc.Type.VPN ||
-        (this.globalPolicy &&
-         this.globalPolicy.AllowOnlyPolicyNetworksToConnect)) {
-      this.autoConnect_ = false;
-    } else {
-      this.autoConnect_ = true;
-    }
-
     this.onCertificateListsChanged_();
     this.updateIsConfigured_();
     this.setShareNetwork_();
@@ -427,9 +412,12 @@
 
     const propertiesToSet = this.getPropertiesToSet_();
     if (this.getSource_() == CrOnc.Source.NONE) {
-      if (!this.autoConnect_) {
-        // Note: Do not set AutoConnect to true, the connection manager will do
-        // that on a successful connection (unless set to false here).
+      // Set 'AutoConnect' to false for VPN or if prohibited by policy.
+      // Note: Do not set AutoConnect to true, the connection manager will do
+      // that on a successful connection (unless set to false here).
+      if (this.type == CrOnc.Type.VPN ||
+          (this.globalPolicy &&
+           this.globalPolicy.AllowOnlyPolicyNetworksToConnect)) {
         CrOnc.setTypeProperty(propertiesToSet, 'AutoConnect', false);
       }
       this.networkingPrivate.createNetwork(
@@ -1295,32 +1283,6 @@
    * @return {boolean}
    * @private
    */
-  configCanAutoConnect_: function() {
-    // Only WiFi can choose whether or not to autoConnect.
-    return this.type == CrOnc.Type.WI_FI;
-  },
-
-  /**
-   * @return {boolean}
-   * @private
-   */
-  autoConnectDisabled_: function() {
-    return this.isAutoConnectEnforcedByPolicy_();
-  },
-
-  /**
-   * @return {boolean}
-   * @private
-   */
-  isAutoConnectEnforcedByPolicy_: function() {
-    return !!this.globalPolicy &&
-        !!this.globalPolicy.AllowOnlyPolicyNetworksToAutoconnect;
-  },
-
-  /**
-   * @return {boolean}
-   * @private
-   */
   selectedUserCertHashIsValid_: function() {
     return !!this.selectedUserCertHash_ &&
         this.selectedUserCertHash_ != NO_CERTS_HASH;